Merge changes from topic "bridged_AP_callback"
* changes:
wifi: Add callback onConnectedClientsOrInfoChanged handling
wifi: Add new callback to support use case in bridged mode
diff --git a/Android.bp b/Android.bp
index 598f4fc..62ac6e7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -349,6 +349,7 @@
":framework-telecomm-sources",
":framework-telephony-common-sources",
":framework-telephony-sources",
+ ":framework-vcn-util-sources",
":framework-wifi-annotations",
":framework-wifi-non-updatable-sources",
":PacProcessor-aidl-sources",
@@ -627,7 +628,6 @@
// in favor of an API stubs dependency in java_library "framework" below.
"mimemap",
"av-types-aidl-java",
- "mediatranscoding_aidl_interface-java",
"soundtrigger_middleware-aidl-java",
"modules-utils-os",
],
@@ -1373,7 +1373,6 @@
// TODO(b/145644363): move this to under StubLibraries.bp or ApiDocs.bp
metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.xml) " +
- "--ignore-classes-on-classpath " +
"--hide-package com.android.server " +
"--hide-package android.audio.policy.configuration.V7_0 " +
"--error UnhiddenSystemApi " +
diff --git a/ApiDocs.bp b/ApiDocs.bp
index 3d6bdbf..5f4f3c2 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -96,7 +96,9 @@
arg_files: [
"core/res/AndroidManifest.xml",
],
- args: metalava_framework_docs_args,
+ args: metalava_framework_docs_args +
+ // Needed for hidden libcore annotations for now.
+ " --ignore-classes-on-classpath ",
write_sdk_values: true,
}
@@ -106,7 +108,10 @@
arg_files: [
"core/res/AndroidManifest.xml",
],
- args: metalava_framework_docs_args + " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\) ",
+ args: metalava_framework_docs_args +
+ // Needed for hidden libcore annotations for now.
+ " --ignore-classes-on-classpath " +
+ " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\) ",
write_sdk_values: true,
}
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 12ee889..0596755 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -50,7 +50,9 @@
":art.module.public.api{.public.stubs.source}",
"**/package.html",
],
- sdk_version: "core_platform",
+ sdk_version: "none",
+ system_modules: "none",
+ java_version: "1.8",
arg_files: ["core/res/AndroidManifest.xml"],
// TODO(b/147699819, b/169090544): remove below aidl includes.
aidl: {
@@ -80,6 +82,7 @@
"android.hardware.usb.gadget-V1.0-java",
"android.hardware.vibrator-V1.3-java",
"framework-protos",
+ "stable.core.platform.api.stubs",
// There are a few classes from modules used as type arguments that
// need to be resolved by metalava. For now, we can use a previously
// finalized stub library to resolve them. If a new class gets added,
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index 31f05ba..6eb44a7 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -1472,6 +1472,7 @@
* <li>Run as soon as possible</li>
* <li>Be exempted from Doze and battery saver restrictions</li>
* <li>Have network access</li>
+ * <li>Less likely to be killed than regular jobs</li>
* </ol>
*
* Since these jobs have stronger guarantees than regular jobs, they will be subject to
@@ -1483,10 +1484,11 @@
* will immediately return {@link JobScheduler#RESULT_FAILURE} if the app does not have
* available quota (and the job will not be successfully scheduled).
*
- * Expedited jobs may only set network constraints. No other constraints are allowed.
+ * Expedited jobs may only set network, storage-not-low, and persistence constraints.
+ * No other constraints are allowed.
*
* Note: Even though expedited jobs are meant to run as soon as possible, they may be
- * deferred if the system is under heavy load or the network constraint is satisfied
+ * deferred if the system is under heavy load or requested constraints are not satisfied.
*
* @see JobInfo#isExpedited()
*/
@@ -1666,9 +1668,10 @@
if (isPeriodic) {
throw new IllegalArgumentException("An expedited job cannot be periodic");
}
- if (constraintFlags != 0 || (flags & ~FLAG_EXPEDITED) != 0) {
+ if ((constraintFlags & ~CONSTRAINT_FLAG_STORAGE_NOT_LOW) != 0
+ || (flags & ~FLAG_EXPEDITED) != 0) {
throw new IllegalArgumentException(
- "An expedited job can only have network constraints");
+ "An expedited job can only have network and storage-not-low constraints");
}
if (triggerContentUris != null && triggerContentUris.length > 0) {
throw new IllegalArgumentException(
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
index d4c78a0..0d3e001 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
@@ -202,6 +202,8 @@
* {@code true}. This will return {@code false} if the job that wasn't requested to run as a
* expedited job, or if it was requested to run as an expedited job but the app didn't have
* any remaining expedited job quota at the time of execution.
+ *
+ * @see JobInfo.Builder#setExpedited(boolean)
*/
public boolean isExpeditedJob() {
return mIsExpedited;
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index 811a700..60dea07 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -36,7 +36,8 @@
"framework_media_annotation",
],
static_libs: [
- "exoplayer2-extractor"
+ "exoplayer2-extractor",
+ "mediatranscoding_aidl_interface-java",
],
jarjar_rules: "jarjar_rules.txt",
@@ -57,10 +58,12 @@
filegroup {
name: "updatable-media-srcs",
srcs: [
+ "java/android/media/MediaFrameworkInitializer.java",
":media-aidl-srcs",
":mediaparceledlistslice-java-srcs",
":mediaparser-srcs",
":mediasession2-java-srcs",
+ ":mediatranscoding-srcs",
],
visibility: ["//frameworks/base"],
}
@@ -98,6 +101,17 @@
path: "java",
}
+filegroup {
+ name: "mediatranscoding-srcs",
+ srcs: [
+ "java/android/media/ApplicationMediaCapabilities.java",
+ "java/android/media/MediaFeature.java",
+ "java/android/media/MediaTranscodeManager.java",
+ "java/android/media/MediaTranscodingException.java",
+ ],
+ path: "java",
+}
+
java_sdk_library {
name: "framework-media",
defaults: ["framework-module-defaults"],
diff --git a/apex/media/framework/api/current.txt b/apex/media/framework/api/current.txt
index 0cc8e52..ce3bcbe 100644
--- a/apex/media/framework/api/current.txt
+++ b/apex/media/framework/api/current.txt
@@ -1,6 +1,26 @@
// Signature format: 2.0
package android.media {
+ public final class ApplicationMediaCapabilities implements android.os.Parcelable {
+ method @NonNull public static android.media.ApplicationMediaCapabilities createFromXml(@NonNull org.xmlpull.v1.XmlPullParser);
+ method public int describeContents();
+ method @NonNull public java.util.List<java.lang.String> getSupportedHdrTypes();
+ method @NonNull public java.util.List<java.lang.String> getSupportedVideoMimeTypes();
+ method public boolean isHdrTypeSupported(@NonNull String);
+ method public boolean isSlowMotionSupported();
+ method public boolean isVideoMimeTypeSupported(@NonNull String);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.ApplicationMediaCapabilities> CREATOR;
+ }
+
+ public static final class ApplicationMediaCapabilities.Builder {
+ ctor public ApplicationMediaCapabilities.Builder();
+ method @NonNull public android.media.ApplicationMediaCapabilities.Builder addSupportedHdrType(@NonNull String);
+ method @NonNull public android.media.ApplicationMediaCapabilities.Builder addSupportedVideoMimeType(@NonNull String);
+ method @NonNull public android.media.ApplicationMediaCapabilities build();
+ method @NonNull public android.media.ApplicationMediaCapabilities.Builder setSlowMotionSupported(boolean);
+ }
+
public class MediaController2 implements java.lang.AutoCloseable {
method public void cancelSessionCommand(@NonNull Object);
method public void close();
@@ -25,6 +45,17 @@
method @Nullable public android.media.Session2Command.Result onSessionCommand(@NonNull android.media.MediaController2, @NonNull android.media.Session2Command, @Nullable android.os.Bundle);
}
+ public final class MediaFeature {
+ ctor public MediaFeature();
+ }
+
+ public static final class MediaFeature.HdrType {
+ field public static final String DOLBY_VISION = "android.media.feature.hdr.dolby_vision";
+ field public static final String HDR10 = "android.media.feature.hdr.hdr10";
+ field public static final String HDR10_PLUS = "android.media.feature.hdr.hdr10_plus";
+ field public static final String HLG = "android.media.feature.hdr.hlg";
+ }
+
public final class MediaParser {
method public boolean advance(@NonNull android.media.MediaParser.SeekableInputReader) throws java.io.IOException;
method @NonNull public static android.media.MediaParser create(@NonNull android.media.MediaParser.OutputConsumer, @NonNull java.lang.String...);
@@ -170,6 +201,12 @@
method public int getNotificationId();
}
+ public class MediaTranscodingException extends java.lang.Exception {
+ }
+
+ public static final class MediaTranscodingException.ServiceNotAvailableException extends android.media.MediaTranscodingException {
+ }
+
public final class Session2Command implements android.os.Parcelable {
ctor public Session2Command(int);
ctor public Session2Command(@NonNull String, @Nullable android.os.Bundle);
diff --git a/apex/media/framework/api/module-lib-current.txt b/apex/media/framework/api/module-lib-current.txt
index 2b69863..ad9114f 100644
--- a/apex/media/framework/api/module-lib-current.txt
+++ b/apex/media/framework/api/module-lib-current.txt
@@ -1,6 +1,11 @@
// Signature format: 2.0
package android.media {
+ public class MediaFrameworkInitializer {
+ method public static void registerServiceWrappers();
+ method public static void setMediaServiceManager(@NonNull android.media.MediaServiceManager);
+ }
+
@Deprecated public final class MediaParceledListSlice<T extends android.os.Parcelable> implements android.os.Parcelable {
ctor @Deprecated public MediaParceledListSlice(@NonNull java.util.List<T>);
method @Deprecated public int describeContents();
diff --git a/apex/media/framework/api/system-current.txt b/apex/media/framework/api/system-current.txt
index d802177..89cf77c 100644
--- a/apex/media/framework/api/system-current.txt
+++ b/apex/media/framework/api/system-current.txt
@@ -1 +1,67 @@
// Signature format: 2.0
+package android.media {
+
+ public final class MediaTranscodeManager {
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingSession enqueueRequest(@NonNull android.media.MediaTranscodeManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodeManager.OnTranscodingFinishedListener) throws java.io.FileNotFoundException, android.media.MediaTranscodingException.ServiceNotAvailableException;
+ field public static final int PRIORITY_REALTIME = 1; // 0x1
+ field public static final int TRANSCODING_TYPE_VIDEO = 1; // 0x1
+ }
+
+ @java.lang.FunctionalInterface public static interface MediaTranscodeManager.OnTranscodingFinishedListener {
+ method public void onTranscodingFinished(@NonNull android.media.MediaTranscodeManager.TranscodingSession);
+ }
+
+ public static final class MediaTranscodeManager.TranscodingRequest {
+ method public int getClientPid();
+ method public int getClientUid();
+ method @NonNull public android.net.Uri getDestinationUri();
+ method public int getPriority();
+ method @NonNull public android.net.Uri getSourceUri();
+ method public int getType();
+ method @Nullable public android.media.MediaFormat getVideoTrackFormat();
+ }
+
+ public static final class MediaTranscodeManager.TranscodingRequest.Builder {
+ ctor public MediaTranscodeManager.TranscodingRequest.Builder();
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest build();
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setClientPid(int);
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setClientUid(int);
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setDestinationUri(@NonNull android.net.Uri);
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setPriority(int);
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setSourceUri(@NonNull android.net.Uri);
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setType(int);
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setVideoTrackFormat(@NonNull android.media.MediaFormat);
+ }
+
+ public static class MediaTranscodeManager.TranscodingRequest.MediaFormatResolver {
+ ctor public MediaTranscodeManager.TranscodingRequest.MediaFormatResolver();
+ method @Nullable public android.media.MediaFormat resolveVideoFormat();
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.MediaFormatResolver setClientCapabilities(@NonNull android.media.ApplicationMediaCapabilities);
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.MediaFormatResolver setSourceVideoFormatHint(@NonNull android.media.MediaFormat);
+ method public boolean shouldTranscode();
+ }
+
+ public static final class MediaTranscodeManager.TranscodingSession {
+ method public void cancel();
+ method @IntRange(from=0, to=100) public int getProgress();
+ method public int getResult();
+ method public int getSessionId();
+ method public int getStatus();
+ method public void setOnProgressUpdateListener(@NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener);
+ method public void setOnProgressUpdateListener(int, @NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener);
+ field public static final int RESULT_CANCELED = 4; // 0x4
+ field public static final int RESULT_ERROR = 3; // 0x3
+ field public static final int RESULT_NONE = 1; // 0x1
+ field public static final int RESULT_SUCCESS = 2; // 0x2
+ field public static final int STATUS_FINISHED = 3; // 0x3
+ field public static final int STATUS_PAUSED = 4; // 0x4
+ field public static final int STATUS_PENDING = 1; // 0x1
+ field public static final int STATUS_RUNNING = 2; // 0x2
+ }
+
+ @java.lang.FunctionalInterface public static interface MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener {
+ method public void onProgressUpdate(@NonNull android.media.MediaTranscodeManager.TranscodingSession, @IntRange(from=0, to=100) int);
+ }
+
+}
+
diff --git a/media/java/android/media/ApplicationMediaCapabilities.java b/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
similarity index 100%
rename from media/java/android/media/ApplicationMediaCapabilities.java
rename to apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
diff --git a/media/java/android/media/MediaFeature.java b/apex/media/framework/java/android/media/MediaFeature.java
similarity index 100%
rename from media/java/android/media/MediaFeature.java
rename to apex/media/framework/java/android/media/MediaFeature.java
diff --git a/media/java/android/media/MediaFrameworkInitializer.java b/apex/media/framework/java/android/media/MediaFrameworkInitializer.java
similarity index 73%
copy from media/java/android/media/MediaFrameworkInitializer.java
copy to apex/media/framework/java/android/media/MediaFrameworkInitializer.java
index 577442e..813ad7b 100644
--- a/media/java/android/media/MediaFrameworkInitializer.java
+++ b/apex/media/framework/java/android/media/MediaFrameworkInitializer.java
@@ -17,20 +17,18 @@
package android.media;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.SystemApi.Client;
+import android.media.MediaTranscodeManager;
import android.app.SystemServiceRegistry;
import android.content.Context;
-import android.media.session.MediaSessionManager;
-
-import com.android.internal.util.Preconditions;
-
-import java.util.Objects;
/**
- * Class for performing registration for all media services
+ * Class for performing registration for all media services on com.android.media apex.
*
- * TODO (b/160513103): Move this class when moving media service code to APEX
* @hide
*/
+@SystemApi(client = Client.MODULE_LIBRARIES)
public class MediaFrameworkInitializer {
private MediaFrameworkInitializer() {
}
@@ -47,9 +45,15 @@
*/
public static void setMediaServiceManager(
@NonNull MediaServiceManager mediaServiceManager) {
- Preconditions.checkState(sMediaServiceManager == null,
- "setMediaServiceManager called twice!");
- sMediaServiceManager = Objects.requireNonNull(mediaServiceManager);
+ if (sMediaServiceManager != null) {
+ throw new IllegalStateException("setMediaServiceManager called twice!");
+ }
+
+ if (mediaServiceManager == null) {
+ throw new NullPointerException("mediaServiceManager is null!");
+ }
+
+ sMediaServiceManager = mediaServiceManager;
}
/** @hide */
@@ -66,9 +70,9 @@
*/
public static void registerServiceWrappers() {
SystemServiceRegistry.registerContextAwareService(
- Context.MEDIA_SESSION_SERVICE,
- MediaSessionManager.class,
- context -> new MediaSessionManager(context)
+ Context.MEDIA_TRANSCODING_SERVICE,
+ MediaTranscodeManager.class,
+ context -> new MediaTranscodeManager(context)
);
}
}
diff --git a/media/java/android/media/MediaTranscodeManager.java b/apex/media/framework/java/android/media/MediaTranscodeManager.java
similarity index 99%
rename from media/java/android/media/MediaTranscodeManager.java
rename to apex/media/framework/java/android/media/MediaTranscodeManager.java
index 705da19..d449289 100644
--- a/media/java/android/media/MediaTranscodeManager.java
+++ b/apex/media/framework/java/android/media/MediaTranscodeManager.java
@@ -28,7 +28,6 @@
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.system.Os;
import android.util.Log;
@@ -104,8 +103,6 @@
public final class MediaTranscodeManager {
private static final String TAG = "MediaTranscodeManager";
- private static final String MEDIA_TRANSCODING_SERVICE = "media.transcoding";
-
/** Maximum number of retry to connect to the service. */
private static final int CONNECT_SERVICE_RETRY_COUNT = 100;
@@ -281,7 +278,10 @@
for (int count = 1; count <= retryCount; count++) {
Log.d(TAG, "Trying to connect to service. Try count: " + count);
IMediaTranscodingService service = IMediaTranscodingService.Stub.asInterface(
- ServiceManager.getService(MEDIA_TRANSCODING_SERVICE));
+ MediaFrameworkInitializer
+ .getMediaServiceManager()
+ .getMediaTranscodingServiceRegisterer()
+ .get());
if (service != null) {
return service;
}
diff --git a/media/java/android/media/MediaTranscodingException.java b/apex/media/framework/java/android/media/MediaTranscodingException.java
similarity index 100%
rename from media/java/android/media/MediaTranscodingException.java
rename to apex/media/framework/java/android/media/MediaTranscodingException.java
diff --git a/cmds/idmap2/idmap2/Lookup.cpp b/cmds/idmap2/idmap2/Lookup.cpp
index 8323d0b..437180d 100644
--- a/cmds/idmap2/idmap2/Lookup.cpp
+++ b/cmds/idmap2/idmap2/Lookup.cpp
@@ -71,7 +71,7 @@
}
// next, try to parse as a package:type/name string
- if (auto resid = am.GetResourceId(res, "", fallback_package)) {
+ if (auto resid = am.GetResourceId(res, "", fallback_package); resid.ok()) {
return *resid;
}
@@ -94,7 +94,7 @@
case Res_value::TYPE_STRING: {
const ResStringPool* pool = am->GetStringPoolForCookie(value.cookie);
out->append("\"");
- if (auto str = pool->string8ObjectAt(value.data)) {
+ if (auto str = pool->string8ObjectAt(value.data); str.ok()) {
out->append(*str);
}
} break;
diff --git a/cmds/idmap2/libidmap2/XmlParser.cpp b/cmds/idmap2/libidmap2/XmlParser.cpp
index 7c55b64..4030b83 100644
--- a/cmds/idmap2/libidmap2/XmlParser.cpp
+++ b/cmds/idmap2/libidmap2/XmlParser.cpp
@@ -98,7 +98,7 @@
switch ((*value).dataType) {
case Res_value::TYPE_STRING: {
- if (auto str = parser_.getStrings().string8ObjectAt((*value).data)) {
+ if (auto str = parser_.getStrings().string8ObjectAt((*value).data); str.ok()) {
return std::string(str->string());
}
break;
diff --git a/core/api/current.txt b/core/api/current.txt
index c2f88d7..c11d2bc 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -10134,6 +10134,7 @@
method public abstract android.content.Context createDisplayContext(@NonNull android.view.Display);
method public abstract android.content.Context createPackageContext(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method @NonNull public android.content.Context createWindowContext(int, @Nullable android.os.Bundle);
+ method @NonNull public android.content.Context createWindowContext(@NonNull android.view.Display, int, @Nullable android.os.Bundle);
method public abstract String[] databaseList();
method public abstract boolean deleteDatabase(String);
method public abstract boolean deleteFile(String);
@@ -19069,6 +19070,20 @@
field public static final int STATE_UNKNOWN = 0; // 0x0
}
+ public final class GnssMeasurementRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public boolean isFullTracking();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssMeasurementRequest> CREATOR;
+ }
+
+ public static final class GnssMeasurementRequest.Builder {
+ ctor public GnssMeasurementRequest.Builder();
+ ctor public GnssMeasurementRequest.Builder(@NonNull android.location.GnssMeasurementRequest);
+ method @NonNull public android.location.GnssMeasurementRequest build();
+ method @NonNull public android.location.GnssMeasurementRequest.Builder setFullTracking(boolean);
+ }
+
public final class GnssMeasurementsEvent implements android.os.Parcelable {
method public int describeContents();
method @NonNull public android.location.GnssClock getClock();
@@ -19295,6 +19310,7 @@
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback, @Nullable android.os.Handler);
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
method @Deprecated public boolean registerGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback);
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback, @Nullable android.os.Handler);
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssNavigationMessageCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssNavigationMessage.Callback);
@@ -19430,26 +19446,6 @@
package android.media {
- public final class ApplicationMediaCapabilities implements android.os.Parcelable {
- method @NonNull public static android.media.ApplicationMediaCapabilities createFromXml(@NonNull org.xmlpull.v1.XmlPullParser);
- method public int describeContents();
- method @NonNull public java.util.List<java.lang.String> getSupportedHdrTypes();
- method @NonNull public java.util.List<java.lang.String> getSupportedVideoMimeTypes();
- method public boolean isHdrTypeSupported(@NonNull String);
- method public boolean isSlowMotionSupported();
- method public boolean isVideoMimeTypeSupported(@NonNull String);
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.media.ApplicationMediaCapabilities> CREATOR;
- }
-
- public static final class ApplicationMediaCapabilities.Builder {
- ctor public ApplicationMediaCapabilities.Builder();
- method @NonNull public android.media.ApplicationMediaCapabilities.Builder addSupportedHdrType(@NonNull String);
- method @NonNull public android.media.ApplicationMediaCapabilities.Builder addSupportedVideoMimeType(@NonNull String);
- method @NonNull public android.media.ApplicationMediaCapabilities build();
- method @NonNull public android.media.ApplicationMediaCapabilities.Builder setSlowMotionSupported(boolean);
- }
-
public class AsyncPlayer {
ctor public AsyncPlayer(String);
method @Deprecated public void play(android.content.Context, android.net.Uri, boolean, int);
@@ -19670,15 +19666,18 @@
public class AudioManager {
method @Deprecated public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener);
method public int abandonAudioFocusRequest(@NonNull android.media.AudioFocusRequest);
+ method public void addOnCommunicationDeviceChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnCommunicationDeviceChangedListener);
method public void adjustStreamVolume(int, int, int);
method public void adjustSuggestedStreamVolume(int, int, int);
method public void adjustVolume(int, int);
+ method public void clearDeviceForCommunication();
method public void dispatchMediaKeyEvent(android.view.KeyEvent);
method public int generateAudioSessionId();
method @NonNull public java.util.List<android.media.AudioPlaybackConfiguration> getActivePlaybackConfigurations();
method @NonNull public java.util.List<android.media.AudioRecordingConfiguration> getActiveRecordingConfigurations();
method public int getAllowedCapturePolicy();
method public int getAudioHwSyncForSession(int);
+ method @Nullable public android.media.AudioDeviceInfo getDeviceForCommunication();
method public android.media.AudioDeviceInfo[] getDevices(int);
method public java.util.List<android.media.MicrophoneInfo> getMicrophones() throws java.io.IOException;
method public int getMode();
@@ -19714,11 +19713,13 @@
method @Deprecated public void registerMediaButtonEventReceiver(android.app.PendingIntent);
method @Deprecated public void registerRemoteControlClient(android.media.RemoteControlClient);
method @Deprecated public boolean registerRemoteController(android.media.RemoteController);
+ method public void removeOnCommunicationDeviceChangedListener(@NonNull android.media.AudioManager.OnCommunicationDeviceChangedListener);
method @Deprecated public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int);
method public int requestAudioFocus(@NonNull android.media.AudioFocusRequest);
method public void setAllowedCapturePolicy(int);
method @Deprecated public void setBluetoothA2dpOn(boolean);
method public void setBluetoothScoOn(boolean);
+ method public boolean setDeviceForCommunication(@NonNull android.media.AudioDeviceInfo);
method public void setMicrophoneMute(boolean);
method public void setMode(int);
method public void setParameters(String);
@@ -19856,6 +19857,10 @@
method public void onAudioFocusChange(int);
}
+ public static interface AudioManager.OnCommunicationDeviceChangedListener {
+ method public void onCommunicationDeviceChanged(@Nullable android.media.AudioDeviceInfo);
+ }
+
public final class AudioMetadata {
method @NonNull public static android.media.AudioMetadataMap createMap();
}
@@ -19907,7 +19912,6 @@
public final class AudioPlaybackConfiguration implements android.os.Parcelable {
method public int describeContents();
method public android.media.AudioAttributes getAudioAttributes();
- method @Nullable public android.media.AudioDeviceInfo getAudioDevice();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioPlaybackConfiguration> CREATOR;
}
@@ -21561,17 +21565,6 @@
field public static final String TRACKS = "android.media.mediaextractor.ntrk";
}
- public final class MediaFeature {
- ctor public MediaFeature();
- }
-
- public static final class MediaFeature.HdrType {
- field public static final String DOLBY_VISION = "android.media.feature.hdr.dolby_vision";
- field public static final String HDR10 = "android.media.feature.hdr.hdr10";
- field public static final String HDR10_PLUS = "android.media.feature.hdr.hdr10_plus";
- field public static final String HLG = "android.media.feature.hdr.hlg";
- }
-
public final class MediaFormat {
ctor public MediaFormat();
ctor public MediaFormat(@NonNull android.media.MediaFormat);
@@ -22592,12 +22585,6 @@
field public static final android.media.MediaTimestamp TIMESTAMP_UNKNOWN;
}
- public class MediaTranscodingException extends java.lang.Exception {
- }
-
- public static final class MediaTranscodingException.ServiceNotAvailableException extends android.media.MediaTranscodingException {
- }
-
public interface MicrophoneDirection {
method public boolean setPreferredMicrophoneDirection(int);
method public boolean setPreferredMicrophoneFieldDimension(@FloatRange(from=-1.0, to=1.0) float);
@@ -33611,8 +33598,8 @@
}
protected static interface ContactsContract.DataColumns {
- field public static final String CARRIER_PRESENCE = "carrier_presence";
- field public static final int CARRIER_PRESENCE_VT_CAPABLE = 1; // 0x1
+ field @Deprecated public static final String CARRIER_PRESENCE = "carrier_presence";
+ field @Deprecated public static final int CARRIER_PRESENCE_VT_CAPABLE = 1; // 0x1
field public static final String DATA1 = "data1";
field public static final String DATA10 = "data10";
field public static final String DATA11 = "data11";
@@ -40665,7 +40652,7 @@
field public static final String KEY_USE_ACS_FOR_RCS_BOOL = "use_acs_for_rcs_bool";
field public static final String KEY_USE_HFA_FOR_PROVISIONING_BOOL = "use_hfa_for_provisioning_bool";
field public static final String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool";
- field public static final String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
+ field @Deprecated public static final String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
field public static final String KEY_USE_RCS_SIP_OPTIONS_BOOL = "use_rcs_sip_options_bool";
field public static final String KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL = "use_wfc_home_network_mode_in_roaming_network_bool";
field public static final String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool";
@@ -40705,9 +40692,12 @@
}
public static final class CarrierConfigManager.Ims {
+ field public static final String KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL = "ims.enable_presence_capability_exchange_bool";
+ field public static final String KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL = "ims.enable_presence_group_subscribe_bool";
field public static final String KEY_ENABLE_PRESENCE_PUBLISH_BOOL = "ims.enable_presence_publish_bool";
field public static final String KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL = "ims.ims_single_registration_required_bool";
field public static final String KEY_PREFIX = "ims.";
+ field public static final String KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL = "ims.rcs_bulk_capability_exchange_bool";
field public static final String KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT = "ims.wifi_off_deferring_time_millis_int";
}
@@ -41363,6 +41353,7 @@
field public static final int SERVICE_OPTION_OUT_OF_ORDER = 34; // 0x22
field public static final int SIGNAL_LOST = -3; // 0xfffffffd
field public static final int SIM_CARD_CHANGED = 2043; // 0x7fb
+ field public static final int SLICE_REJECTED = 2252; // 0x8cc
field public static final int SYNCHRONIZATION_FAILURE = 2184; // 0x888
field public static final int TEST_LOOPBACK_REGULAR_DEACTIVATION = 2196; // 0x894
field public static final int TETHERED_CALL_ACTIVE = -6; // 0xfffffffa
@@ -42272,6 +42263,7 @@
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean doesSwitchMultiSimConfigTriggerReboot();
method public int getActiveModemCount();
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public java.util.List<android.telephony.CellInfo> getAllCellInfo();
+ method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getCallComposerStatus();
method public int getCallState();
method public int getCardIdForDefaultEuicc();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @WorkerThread public android.os.PersistableBundle getCarrierConfig();
@@ -42368,6 +42360,7 @@
method @Deprecated public String sendEnvelopeWithStatus(String);
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 setCallComposerStatus(int);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabledForReason(int, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setForbiddenPlmns(@NonNull java.util.List<java.lang.String>);
@@ -42408,6 +42401,8 @@
field public static final int APPTYPE_USIM = 2; // 0x2
field public static final int AUTHTYPE_EAP_AKA = 129; // 0x81
field public static final int AUTHTYPE_EAP_SIM = 128; // 0x80
+ field public static final int CALL_COMPOSER_STATUS_OFF = 0; // 0x0
+ field public static final int CALL_COMPOSER_STATUS_ON = 1; // 0x1
field public static final int CALL_STATE_IDLE = 0; // 0x0
field public static final int CALL_STATE_OFFHOOK = 2; // 0x2
field public static final int CALL_STATE_RINGING = 1; // 0x1
@@ -46680,6 +46675,7 @@
method public java.util.List<android.view.InputDevice.MotionRange> getMotionRanges();
method public String getName();
method public int getProductId();
+ method @NonNull public android.hardware.SensorManager getSensorManager();
method public int getSources();
method public int getVendorId();
method public android.os.Vibrator getVibrator();
@@ -52150,6 +52146,7 @@
method public void setCookieAndSequence(int, int);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.view.textservice.SuggestionsInfo> CREATOR;
+ field public static final int RESULT_ATTR_DONT_SHOW_UI_FOR_SUGGESTIONS = 16; // 0x10
field public static final int RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = 4; // 0x4
field public static final int RESULT_ATTR_IN_THE_DICTIONARY = 1; // 0x1
field public static final int RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR = 8; // 0x8
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index cbb3bea..94a6576 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -80,6 +80,17 @@
public class MediaMetadataRetriever implements java.lang.AutoCloseable {
field public static final int METADATA_KEY_VIDEO_CODEC_MIME_TYPE = 40; // 0x28
+ field public static final int METADATA_KEY_XMP_LENGTH = 42; // 0x2a
+ field public static final int METADATA_KEY_XMP_OFFSET = 41; // 0x29
+ }
+
+ public class MediaServiceManager {
+ method @NonNull public android.media.MediaServiceManager.ServiceRegisterer getMediaSessionServiceRegisterer();
+ method @NonNull public android.media.MediaServiceManager.ServiceRegisterer getMediaTranscodingServiceRegisterer();
+ }
+
+ public static final class MediaServiceManager.ServiceRegisterer {
+ method @Nullable public android.os.IBinder get();
}
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 0f1adc0..8fd48a5 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -4316,7 +4316,7 @@
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@NonNull String);
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String);
method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.UPDATE_APP_OPS_STATS}) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
- method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.LOCATION_HARDWARE}) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
@@ -4593,68 +4593,6 @@
field @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT) public static final int RADIO_TUNER = 1998; // 0x7ce
}
- public final class MediaTranscodeManager {
- method @NonNull public android.media.MediaTranscodeManager.TranscodingSession enqueueRequest(@NonNull android.media.MediaTranscodeManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodeManager.OnTranscodingFinishedListener) throws java.io.FileNotFoundException, android.media.MediaTranscodingException.ServiceNotAvailableException;
- field public static final int PRIORITY_REALTIME = 1; // 0x1
- field public static final int TRANSCODING_TYPE_VIDEO = 1; // 0x1
- }
-
- @java.lang.FunctionalInterface public static interface MediaTranscodeManager.OnTranscodingFinishedListener {
- method public void onTranscodingFinished(@NonNull android.media.MediaTranscodeManager.TranscodingSession);
- }
-
- public static final class MediaTranscodeManager.TranscodingRequest {
- method public int getClientPid();
- method public int getClientUid();
- method @NonNull public android.net.Uri getDestinationUri();
- method public int getPriority();
- method @NonNull public android.net.Uri getSourceUri();
- method public int getType();
- method @Nullable public android.media.MediaFormat getVideoTrackFormat();
- }
-
- public static final class MediaTranscodeManager.TranscodingRequest.Builder {
- ctor public MediaTranscodeManager.TranscodingRequest.Builder();
- method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest build();
- method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setClientPid(int);
- method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setClientUid(int);
- method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setDestinationUri(@NonNull android.net.Uri);
- method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setPriority(int);
- method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setSourceUri(@NonNull android.net.Uri);
- method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setType(int);
- method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setVideoTrackFormat(@NonNull android.media.MediaFormat);
- }
-
- public static class MediaTranscodeManager.TranscodingRequest.MediaFormatResolver {
- ctor public MediaTranscodeManager.TranscodingRequest.MediaFormatResolver();
- method @Nullable public android.media.MediaFormat resolveVideoFormat();
- method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.MediaFormatResolver setClientCapabilities(@NonNull android.media.ApplicationMediaCapabilities);
- method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.MediaFormatResolver setSourceVideoFormatHint(@NonNull android.media.MediaFormat);
- method public boolean shouldTranscode();
- }
-
- public static final class MediaTranscodeManager.TranscodingSession {
- method public void cancel();
- method @IntRange(from=0, to=100) public int getProgress();
- method public int getResult();
- method public int getSessionId();
- method public int getStatus();
- method public void setOnProgressUpdateListener(@NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener);
- method public void setOnProgressUpdateListener(int, @NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener);
- field public static final int RESULT_CANCELED = 4; // 0x4
- field public static final int RESULT_ERROR = 3; // 0x3
- field public static final int RESULT_NONE = 1; // 0x1
- field public static final int RESULT_SUCCESS = 2; // 0x2
- field public static final int STATUS_FINISHED = 3; // 0x3
- field public static final int STATUS_PAUSED = 4; // 0x4
- field public static final int STATUS_PENDING = 1; // 0x1
- field public static final int STATUS_RUNNING = 2; // 0x2
- }
-
- @java.lang.FunctionalInterface public static interface MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener {
- method public void onProgressUpdate(@NonNull android.media.MediaTranscodeManager.TranscodingSession, @IntRange(from=0, to=100) int);
- }
-
public class PlayerProxy {
method public void pause();
method public void setPan(float);
@@ -7670,12 +7608,14 @@
method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.os.connectivity.WifiBatteryStats getWifiBatteryStats();
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportFullWifiLockAcquiredFromSource(@NonNull android.os.WorkSource);
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportFullWifiLockReleasedFromSource(@NonNull android.os.WorkSource);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportMobileRadioPowerState(boolean, int) throws java.lang.RuntimeException;
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiBatchedScanStartedFromSource(@NonNull android.os.WorkSource, @IntRange(from=0) int);
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiBatchedScanStoppedFromSource(@NonNull android.os.WorkSource);
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiMulticastDisabled(@NonNull android.os.WorkSource);
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiMulticastEnabled(@NonNull android.os.WorkSource);
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiOff();
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiOn();
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiRadioPowerState(boolean, int) throws java.lang.RuntimeException;
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiRssiChanged(@IntRange(from=0xffffff81, to=0) int);
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiScanStartedFromSource(@NonNull android.os.WorkSource);
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiScanStoppedFromSource(@NonNull android.os.WorkSource);
@@ -8062,7 +8002,7 @@
method @RequiresPermission(anyOf={android.Manifest.permission.RECOVERY, android.Manifest.permission.REBOOT}) public static void prepareForUnattendedUpdate(@NonNull android.content.Context, @NonNull String, @Nullable android.content.IntentSender) throws java.io.IOException;
method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void processPackage(android.content.Context, java.io.File, android.os.RecoverySystem.ProgressListener, android.os.Handler) throws java.io.IOException;
method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void processPackage(android.content.Context, java.io.File, android.os.RecoverySystem.ProgressListener) throws java.io.IOException;
- method @RequiresPermission(anyOf={android.Manifest.permission.RECOVERY, android.Manifest.permission.REBOOT}) public static void rebootAndApply(@NonNull android.content.Context, @NonNull String, @NonNull String) throws java.io.IOException;
+ method @Deprecated @RequiresPermission(android.Manifest.permission.RECOVERY) public static void rebootAndApply(@NonNull android.content.Context, @NonNull String, @NonNull String) throws java.io.IOException;
method @RequiresPermission(anyOf={android.Manifest.permission.RECOVERY, android.Manifest.permission.REBOOT}) public static void rebootAndApply(@NonNull android.content.Context, @NonNull String, boolean) throws java.io.IOException;
method @RequiresPermission(allOf={android.Manifest.permission.RECOVERY, android.Manifest.permission.REBOOT}) public static void rebootWipeAb(android.content.Context, java.io.File, String) throws java.io.IOException;
method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void scheduleUpdateOnBoot(android.content.Context, java.io.File) throws java.io.IOException;
@@ -11527,6 +11467,7 @@
method public int getPduSessionId();
method public int getProtocolType();
method public long getRetryDurationMillis();
+ method @Nullable public android.telephony.data.SliceInfo getSliceInfo();
method @Deprecated public int getSuggestedRetryTime();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.DataCallResponse> CREATOR;
@@ -11561,6 +11502,7 @@
method @NonNull public android.telephony.data.DataCallResponse.Builder setPduSessionId(int);
method @NonNull public android.telephony.data.DataCallResponse.Builder setProtocolType(int);
method @NonNull public android.telephony.data.DataCallResponse.Builder setRetryDurationMillis(long);
+ method @NonNull public android.telephony.data.DataCallResponse.Builder setSliceInfo(@Nullable android.telephony.data.SliceInfo);
method @Deprecated @NonNull public android.telephony.data.DataCallResponse.Builder setSuggestedRetryTime(int);
}
@@ -11633,7 +11575,7 @@
method public void setDataProfile(@NonNull java.util.List<android.telephony.data.DataProfile>, boolean, @NonNull android.telephony.data.DataServiceCallback);
method public void setInitialAttachApn(@NonNull android.telephony.data.DataProfile, boolean, @NonNull android.telephony.data.DataServiceCallback);
method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @NonNull android.telephony.data.DataServiceCallback);
- method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @IntRange(from=0, to=15) int, @NonNull android.telephony.data.DataServiceCallback);
+ method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @IntRange(from=0, to=15) int, @Nullable android.telephony.data.SliceInfo, @NonNull android.telephony.data.DataServiceCallback);
method public void startHandover(int, @NonNull android.telephony.data.DataServiceCallback);
}
@@ -11668,6 +11610,32 @@
method public final void updateQualifiedNetworkTypes(int, @NonNull java.util.List<java.lang.Integer>);
}
+ public final class SliceInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @IntRange(from=android.telephony.data.SliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.SliceInfo.MAX_SLICE_DIFFERENTIATOR) public int getMappedHplmnSliceDifferentiator();
+ method public int getMappedHplmnSliceServiceType();
+ method @IntRange(from=android.telephony.data.SliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.SliceInfo.MAX_SLICE_DIFFERENTIATOR) public int getSliceDifferentiator();
+ method public int getSliceServiceType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.SliceInfo> CREATOR;
+ field public static final int MAX_SLICE_DIFFERENTIATOR = 16777214; // 0xfffffe
+ field public static final int MIN_SLICE_DIFFERENTIATOR = -1; // 0xffffffff
+ field public static final int SLICE_DIFFERENTIATOR_NO_SLICE = -1; // 0xffffffff
+ field public static final int SLICE_SERVICE_TYPE_EMBB = 1; // 0x1
+ field public static final int SLICE_SERVICE_TYPE_MIOT = 3; // 0x3
+ field public static final int SLICE_SERVICE_TYPE_NONE = 0; // 0x0
+ field public static final int SLICE_SERVICE_TYPE_URLLC = 2; // 0x2
+ }
+
+ public static final class SliceInfo.Builder {
+ ctor public SliceInfo.Builder();
+ method @NonNull public android.telephony.data.SliceInfo build();
+ method @NonNull public android.telephony.data.SliceInfo.Builder setMappedHplmnSliceDifferentiator(@IntRange(from=android.telephony.data.SliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.SliceInfo.MAX_SLICE_DIFFERENTIATOR) int);
+ method @NonNull public android.telephony.data.SliceInfo.Builder setMappedHplmnSliceServiceType(int);
+ method @NonNull public android.telephony.data.SliceInfo.Builder setSliceDifferentiator(@IntRange(from=android.telephony.data.SliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.SliceInfo.MAX_SLICE_DIFFERENTIATOR) int);
+ method @NonNull public android.telephony.data.SliceInfo.Builder setSliceServiceType(int);
+ }
+
}
package android.telephony.euicc {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index f51bb95..5b86e8d 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -381,11 +381,14 @@
field public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
field public static final int OPERATION_CREATE_AND_MANAGE_USER = 5; // 0x5
field public static final int OPERATION_LOCK_NOW = 1; // 0x1
+ field public static final int OPERATION_LOGOUT_USER = 9; // 0x9
field public static final int OPERATION_REBOOT = 7; // 0x7
field public static final int OPERATION_REMOVE_USER = 6; // 0x6
+ field public static final int OPERATION_SET_USER_RESTRICTION = 10; // 0xa
field public static final int OPERATION_START_USER_IN_BACKGROUND = 3; // 0x3
field public static final int OPERATION_STOP_USER = 4; // 0x4
field public static final int OPERATION_SWITCH_USER = 2; // 0x2
+ field public static final int OPERATION_WIPE_DATA = 8; // 0x8
}
public static final class SecurityLog.SecurityEvent implements android.os.Parcelable {
@@ -985,6 +988,7 @@
}
public class AudioManager {
+ method @Nullable public static android.media.AudioDeviceInfo getDeviceInfoFromType(int);
method public boolean hasRegisteredDynamicPolicy();
}
@@ -2457,6 +2461,13 @@
field public static final int FEATURE_WINDOW_TOKENS = 2; // 0x2
}
+ public final class StartingWindowInfo implements android.os.Parcelable {
+ ctor public StartingWindowInfo();
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.window.StartingWindowInfo> CREATOR;
+ }
+
public final class TaskAppearedInfo implements android.os.Parcelable {
ctor public TaskAppearedInfo(@NonNull android.app.ActivityManager.RunningTaskInfo, @NonNull android.view.SurfaceControl);
method public int describeContents();
@@ -2468,7 +2479,7 @@
public class TaskOrganizer extends android.window.WindowOrganizer {
ctor public TaskOrganizer();
- method @BinderThread public void addStartingWindow(@NonNull android.app.ActivityManager.RunningTaskInfo, @NonNull android.os.IBinder);
+ method @BinderThread public void addStartingWindow(@NonNull android.window.StartingWindowInfo, @NonNull android.os.IBinder);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void createRootTask(int, int, @Nullable android.os.IBinder);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public boolean deleteRootTask(@NonNull android.window.WindowContainerToken);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public java.util.List<android.app.ActivityManager.RunningTaskInfo> getChildTasks(@NonNull android.window.WindowContainerToken, @NonNull int[]);
@@ -2479,7 +2490,7 @@
method @BinderThread public void onTaskInfoChanged(@NonNull android.app.ActivityManager.RunningTaskInfo);
method @BinderThread public void onTaskVanished(@NonNull android.app.ActivityManager.RunningTaskInfo);
method @CallSuper @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public java.util.List<android.window.TaskAppearedInfo> registerOrganizer();
- method @BinderThread public void removeStartingWindow(@NonNull android.app.ActivityManager.RunningTaskInfo);
+ method @BinderThread public void removeStartingWindow(int);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void setInterceptBackPressedOnTaskRoot(@NonNull android.window.WindowContainerToken, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void setLaunchRoot(int, @NonNull android.window.WindowContainerToken);
method @CallSuper @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void unregisterOrganizer();
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 8e50184..1fa7fa2 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -2120,6 +2120,10 @@
/**
* Sets the strokeWidth and color of the accessibility focus rectangle.
+ * <p>
+ * <strong>Note:</strong> This setting persists until this or another active
+ * AccessibilityService changes it or the device reboots.
+ * </p>
*
* @param strokeWidth The stroke width of the rectangle in pixels.
* Setting this value to zero results in no focus rectangle being drawn.
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 6d564a3..69482bc 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -90,6 +90,7 @@
import android.hardware.display.DisplayManagerGlobal;
import android.inputmethodservice.InputMethodService;
import android.media.MediaFrameworkInitializer;
+import android.media.MediaFrameworkPlatformInitializer;
import android.media.MediaServiceManager;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
@@ -492,6 +493,11 @@
Bundle mCoreSettings = null;
+ /**
+ * The lock word for the {@link #mCoreSettings}.
+ */
+ private final Object mCoreSettingsLock = new Object();
+
boolean mHasImeComponent = false;
/** Activity client record, used for bookkeeping for the real {@link Activity} instance. */
@@ -4955,7 +4961,7 @@
}
private void handleSetCoreSettings(Bundle coreSettings) {
- synchronized (mResourcesManager) {
+ synchronized (mCoreSettingsLock) {
mCoreSettings = coreSettings;
}
onCoreSettingsChange();
@@ -4971,6 +4977,8 @@
private boolean updateDebugViewAttributeState() {
boolean previousState = View.sDebugViewAttributes;
+ // mCoreSettings is only updated from the main thread, while this function is only called
+ // from main thread as well, so no need to lock here.
View.sDebugViewAttributesApplicationPackage = mCoreSettings.getString(
Settings.Global.DEBUG_VIEW_ATTRIBUTES_APPLICATION_PACKAGE, "");
String currentPackage = (mBoundApplication != null && mBoundApplication.appInfo != null)
@@ -6267,6 +6275,8 @@
}
}
+ // mCoreSettings is only updated from the main thread, while this function is only called
+ // from main thread as well, so no need to lock here.
GraphicsEnvironment.getInstance().setup(context, mCoreSettings);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -6448,6 +6458,8 @@
}
updateDefaultDensity();
+ // mCoreSettings is only updated from the main thread, while this function is only called
+ // from main thread as well, so no need to lock here.
final String use24HourSetting = mCoreSettings.getString(Settings.System.TIME_12_24);
Boolean is24Hr = null;
if (use24HourSetting != null) {
@@ -7468,12 +7480,17 @@
}
}
- public Bundle getCoreSettings() {
- return mCoreSettings;
+ /**
+ * Caller should NEVER mutate the Bundle returned from here
+ */
+ Bundle getCoreSettings() {
+ synchronized (mCoreSettingsLock) {
+ return mCoreSettings;
+ }
}
public int getIntCoreSetting(String key, int defaultValue) {
- synchronized (mResourcesManager) {
+ synchronized (mCoreSettingsLock) {
if (mCoreSettings != null) {
return mCoreSettings.getInt(key, defaultValue);
}
@@ -7485,7 +7502,7 @@
* Get the string value of the given key from core settings.
*/
public String getStringCoreSetting(String key, String defaultValue) {
- synchronized (mResourcesManager) {
+ synchronized (mCoreSettingsLock) {
if (mCoreSettings != null) {
return mCoreSettings.getString(key, defaultValue);
}
@@ -7494,7 +7511,7 @@
}
float getFloatCoreSetting(String key, float defaultValue) {
- synchronized (mResourcesManager) {
+ synchronized (mCoreSettingsLock) {
if (mCoreSettings != null) {
return mCoreSettings.getFloat(key, defaultValue);
}
@@ -7701,6 +7718,7 @@
public static void initializeMainlineModules() {
TelephonyFrameworkInitializer.setTelephonyServiceManager(new TelephonyServiceManager());
StatsFrameworkInitializer.setStatsServiceManager(new StatsServiceManager());
+ MediaFrameworkPlatformInitializer.setMediaServiceManager(new MediaServiceManager());
MediaFrameworkInitializer.setMediaServiceManager(new MediaServiceManager());
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 124cf71..700d8ff 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2468,8 +2468,9 @@
return context;
}
+ @NonNull
@Override
- public @NonNull WindowContext createWindowContext(int type, Bundle options) {
+ public WindowContext createWindowContext(int type, @NonNull Bundle options) {
if (getDisplay() == null) {
throw new UnsupportedOperationException("WindowContext can only be created from "
+ "other visual contexts, such as Activity or one created with "
@@ -2478,13 +2479,26 @@
return new WindowContext(this, type, options);
}
- ContextImpl createBaseWindowContext(IBinder token) {
+ @NonNull
+ @Override
+ public WindowContext createWindowContext(@NonNull Display display, int type,
+ @NonNull Bundle options) {
+ if (display == null) {
+ throw new IllegalArgumentException("Display must not be null");
+ }
+ return new WindowContext(this, display, type, options);
+ }
+
+ ContextImpl createBaseWindowContext(IBinder token, Display display) {
ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag,
mSplitName, token, mUser, mFlags, mClassLoader, null);
// Window contexts receive configurations directly from the server and as such do not
// need to override their display in ResourcesManager.
context.mForceDisplayOverrideInResources = false;
context.mContextType = CONTEXT_TYPE_WINDOW_CONTEXT;
+ if (display != null) {
+ context.mDisplay = display;
+ }
return context;
}
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 1ac0a65..523c155 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -191,7 +191,7 @@
*/
IBinder requestStartActivityPermissionToken(in IBinder delegatorToken);
- void releaseSomeActivities(in IApplicationThread app);
+ oneway void releaseSomeActivities(in IApplicationThread app);
Bitmap getTaskDescriptionIcon(in String filename, int userId);
void registerTaskStackListener(in ITaskStackListener listener);
void unregisterTaskStackListener(in ITaskStackListener listener);
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 99785e1..50853a3 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -729,6 +729,23 @@
}
}
+ private StrictMode.VmPolicy allowVmViolations() {
+ if (mActivityThread == null) {
+ // When LoadedApk is used without an ActivityThread (usually in a
+ // zygote context), don't call into StrictMode, as it initializes
+ // the binder subsystem, which we don't want.
+ return null;
+ }
+
+ return StrictMode.allowVmViolations();
+ }
+
+ private void setVmPolicy(StrictMode.VmPolicy policy) {
+ if (mActivityThread != null && policy != null) {
+ StrictMode.setVmPolicy(policy);
+ }
+ }
+
private void createOrUpdateClassLoaderLocked(List<String> addedPaths) {
if (mPackageName.equals("android")) {
// Note: This branch is taken for system server and we don't need to setup
@@ -984,13 +1001,20 @@
// Temporarily disable logging of disk reads on the Looper thread as this is necessary -
// and the loader will access the directory anyway if we don't check it.
- StrictMode.ThreadPolicy oldPolicy = allowThreadDiskReads();
+ StrictMode.ThreadPolicy oldThreadPolicy = allowThreadDiskReads();
+
+ // Also disable logging of access to /data/user before CE storage is unlocked. The check
+ // below will return false (because the directory name we pass will not match the
+ // encrypted one), but that's correct.
+ StrictMode.VmPolicy oldVmPolicy = allowVmViolations();
+
try {
// We are constructing a classloader for a different package. It is likely,
// but not certain, that we can't acccess its app data dir - so check.
return new File(mDataDir).canExecute();
} finally {
- setThreadPolicy(oldPolicy);
+ setThreadPolicy(oldThreadPolicy);
+ setVmPolicy(oldVmPolicy);
}
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 4afbfbf..48d2dfe 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -104,8 +104,8 @@
import android.location.LocationManager;
import android.media.AudioManager;
import android.media.MediaFrameworkInitializer;
+import android.media.MediaFrameworkPlatformInitializer;
import android.media.MediaRouter;
-import android.media.MediaTranscodeManager;
import android.media.midi.IMidiManager;
import android.media.midi.MidiManager;
import android.media.musicrecognition.IMusicRecognitionManager;
@@ -312,15 +312,6 @@
return new AudioManager(ctx);
}});
- registerService(Context.MEDIA_TRANSCODING_SERVICE, MediaTranscodeManager.class,
- new CachedServiceFetcher<MediaTranscodeManager>() {
- @Override
- public MediaTranscodeManager createService(ContextImpl ctx)
- throws ServiceNotFoundException {
- return new MediaTranscodeManager(ctx);
- }
- });
-
registerService(Context.MEDIA_ROUTER_SERVICE, MediaRouter.class,
new CachedServiceFetcher<MediaRouter>() {
@Override
@@ -1401,6 +1392,7 @@
WifiFrameworkInitializer.registerServiceWrappers();
StatsFrameworkInitializer.registerServiceWrappers();
RollbackManagerFrameworkInitializer.initialize();
+ MediaFrameworkPlatformInitializer.registerServiceWrappers();
MediaFrameworkInitializer.registerServiceWrappers();
} finally {
// If any of the above code throws, we're in a pretty bad shape and the process
diff --git a/core/java/android/app/WindowContext.java b/core/java/android/app/WindowContext.java
index 5f72bac..14ed414 100644
--- a/core/java/android/app/WindowContext.java
+++ b/core/java/android/app/WindowContext.java
@@ -26,6 +26,7 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
+import android.view.Display;
import android.view.IWindowManager;
import android.view.WindowManagerGlobal;
import android.view.WindowManagerImpl;
@@ -59,13 +60,27 @@
* @hide
*/
public WindowContext(@NonNull Context base, int type, @Nullable Bundle options) {
+ this(base, null /* display */, type, options);
+ }
+
+ /**
+ * Default constructor. Will generate a {@link WindowTokenClient} and attach this context to
+ * the token.
+ *
+ * @param base Base {@link Context} for this new instance.
+ * @param display the {@link Display} to override.
+ * @param type Window type to be used with this context.
+ * @hide
+ */
+ public WindowContext(@NonNull Context base, @Nullable Display display, int type,
+ @Nullable Bundle options) {
// Correct base context will be built once the token is resolved, so passing 'null' here.
super(null /* base */);
mWms = WindowManagerGlobal.getWindowManagerService();
mToken = new WindowTokenClient();
- final ContextImpl contextImpl = createBaseWindowContext(base, mToken);
+ final ContextImpl contextImpl = createBaseWindowContext(base, mToken, display);
attachBaseContext(contextImpl);
contextImpl.setOuterContext(this);
@@ -93,9 +108,10 @@
Reference.reachabilityFence(this);
}
- private static ContextImpl createBaseWindowContext(Context outer, IBinder token) {
+ private static ContextImpl createBaseWindowContext(Context outer, IBinder token,
+ Display display) {
final ContextImpl contextImpl = ContextImpl.getImpl(outer);
- return contextImpl.createBaseWindowContext(token);
+ return contextImpl.createBaseWindowContext(token, display);
}
@Override
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 2a79c72..a154396 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -54,7 +54,6 @@
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.graphics.Bitmap;
-import android.net.NetworkUtils;
import android.net.PrivateDnsConnectivityChecker;
import android.net.ProxyInfo;
import android.net.Uri;
@@ -92,6 +91,7 @@
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.net.NetworkUtilsInternal;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.Preconditions;
import com.android.org.conscrypt.TrustedCertificateStore;
@@ -2615,6 +2615,15 @@
/** @hide */
@TestApi
public static final int OPERATION_REBOOT = 7;
+ /** @hide */
+ @TestApi
+ public static final int OPERATION_WIPE_DATA = 8;
+ /** @hide */
+ @TestApi
+ public static final int OPERATION_LOGOUT_USER = 9;
+ /** @hide */
+ @TestApi
+ public static final int OPERATION_SET_USER_RESTRICTION = 10;
private static final String PREFIX_OPERATION = "OPERATION_";
@@ -2626,7 +2635,10 @@
OPERATION_STOP_USER,
OPERATION_CREATE_AND_MANAGE_USER,
OPERATION_REMOVE_USER,
- OPERATION_REBOOT
+ OPERATION_REBOOT,
+ OPERATION_WIPE_DATA,
+ OPERATION_LOGOUT_USER,
+ OPERATION_SET_USER_RESTRICTION
})
@Retention(RetentionPolicy.SOURCE)
public static @interface DevicePolicyOperation {
@@ -11973,7 +11985,7 @@
return PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
}
- if (NetworkUtils.isWeaklyValidatedHostname(privateDnsHost)) {
+ if (NetworkUtilsInternal.isWeaklyValidatedHostname(privateDnsHost)) {
if (!PrivateDnsConnectivityChecker.canConnectToPrivateDnsServer(privateDnsHost)) {
return PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING;
}
@@ -12677,21 +12689,4 @@
}
}
}
-
- // TODO(b/175392542): remove if not needed by ManagedProvisioning app anymore
- /**
- * Used by ManagedProvisioning app to factory reset the device when DO cannto be provisioned.
- *
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.MASTER_CLEAR)
- public void factoryReset(String reason) {
- if (mService != null) {
- try {
- mService.factoryReset(reason);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
- }
- }
}
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index a0d2977..ce2fd4f 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -231,13 +231,7 @@
* Returns the profile owner component for the given user, or {@code null} if there is not one.
*/
@Nullable
- public abstract ComponentName getProfileOwnerAsUser(@UserIdInt int userId);
-
- /**
- * Returns the user id of the device owner, or {@link UserHandle#USER_NULL} if there is not one.
- */
- @UserIdInt
- public abstract int getDeviceOwnerUserId();
+ public abstract ComponentName getProfileOwnerAsUser(int userHandle);
/**
* Returns whether the given package is a device owner or a profile owner in the calling user.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index a81b506..bcc90f7 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -488,6 +488,4 @@
boolean canProfileOwnerResetPasswordWhenLocked(int userId);
void setNextOperationSafety(int operation, boolean safe);
- // TODO(b/175392542): remove if not needed by ManagedProvisioning app anymore
- void factoryReset(String reason);
}
diff --git a/core/java/android/app/people/PeopleSpaceTile.java b/core/java/android/app/people/PeopleSpaceTile.java
index f60e42f..95739f3 100644
--- a/core/java/android/app/people/PeopleSpaceTile.java
+++ b/core/java/android/app/people/PeopleSpaceTile.java
@@ -17,6 +17,7 @@
package android.app.people;
import android.annotation.NonNull;
+import android.app.Person;
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
@@ -44,6 +45,7 @@
private int mUid;
private Uri mContactUri;
private String mPackageName;
+ private String mStatusText;
private long mLastInteractionTimestamp;
private boolean mIsImportantConversation;
private boolean mIsHiddenConversation;
@@ -61,6 +63,7 @@
mContactUri = b.mContactUri;
mUid = b.mUid;
mPackageName = b.mPackageName;
+ mStatusText = b.mStatusText;
mLastInteractionTimestamp = b.mLastInteractionTimestamp;
mIsImportantConversation = b.mIsImportantConversation;
mIsHiddenConversation = b.mIsHiddenConversation;
@@ -95,6 +98,10 @@
return mPackageName;
}
+ public String getStatusText() {
+ return mStatusText;
+ }
+
/** Returns the timestamp of the last interaction. */
public long getLastInteractionTimestamp() {
return mLastInteractionTimestamp;
@@ -148,6 +155,7 @@
builder.setContactUri(mContactUri);
builder.setUid(mUid);
builder.setPackageName(mPackageName);
+ builder.setStatusText(mStatusText);
builder.setLastInteractionTimestamp(mLastInteractionTimestamp);
builder.setIsImportantConversation(mIsImportantConversation);
builder.setIsHiddenConversation(mIsHiddenConversation);
@@ -165,6 +173,7 @@
private Uri mContactUri;
private int mUid;
private String mPackageName;
+ private String mStatusText;
private long mLastInteractionTimestamp;
private boolean mIsImportantConversation;
private boolean mIsHiddenConversation;
@@ -188,6 +197,16 @@
mUserIcon = convertDrawableToIcon(launcherApps.getShortcutIconDrawable(info, 0));
mUid = info.getUserId();
mPackageName = info.getPackage();
+ mContactUri = getContactUri(info);
+ }
+
+ private Uri getContactUri(ShortcutInfo info) {
+ if (info.getPersons() == null || info.getPersons().length != 1) {
+ return null;
+ }
+ // TODO(b/175584929): Update to use the Uri from PeopleService directly
+ Person person = info.getPersons()[0];
+ return person.getUri() == null ? null : Uri.parse(person.getUri());
}
/** Sets the ID for the tile. */
@@ -226,6 +245,12 @@
return this;
}
+ /** Sets the status text. */
+ public Builder setStatusText(String statusText) {
+ mStatusText = statusText;
+ return this;
+ }
+
/** Sets the last interaction timestamp. */
public Builder setLastInteractionTimestamp(long lastInteractionTimestamp) {
mLastInteractionTimestamp = lastInteractionTimestamp;
@@ -279,8 +304,10 @@
mId = in.readString();
mUserName = in.readCharSequence();
mUserIcon = in.readParcelable(Icon.class.getClassLoader());
+ mContactUri = in.readParcelable(Uri.class.getClassLoader());
mUid = in.readInt();
mPackageName = in.readString();
+ mStatusText = in.readString();
mLastInteractionTimestamp = in.readLong();
mIsImportantConversation = in.readBoolean();
mIsHiddenConversation = in.readBoolean();
@@ -300,8 +327,10 @@
dest.writeString(mId);
dest.writeCharSequence(mUserName);
dest.writeParcelable(mUserIcon, flags);
+ dest.writeParcelable(mContactUri, flags);
dest.writeInt(mUid);
dest.writeString(mPackageName);
+ dest.writeString(mStatusText);
dest.writeLong(mLastInteractionTimestamp);
dest.writeBoolean(mIsImportantConversation);
dest.writeBoolean(mIsHiddenConversation);
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 1713a0c..406fe8d 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -2967,6 +2967,16 @@
}
});
}
+ synchronized (mBluetoothConnectionCallbackExecutorMap) {
+ if (!mBluetoothConnectionCallbackExecutorMap.isEmpty()) {
+ try {
+ mService.registerBluetoothConnectionCallback(mConnectionCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "onBluetoothServiceUp: Failed to register bluetooth"
+ + "connection callback", e);
+ }
+ }
+ }
}
public void onBluetoothServiceDown() {
@@ -3616,25 +3626,25 @@
return false;
}
- // If the callback map is empty, we register the service-to-app callback
- if (mBluetoothConnectionCallbackExecutorMap.isEmpty()) {
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- if (!mService.registerBluetoothConnectionCallback(mConnectionCallback)) {
- return false;
- }
- }
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- mBluetoothConnectionCallbackExecutorMap.remove(callback);
- } finally {
- mServiceLock.readLock().unlock();
- }
- }
-
- // Adds the passed in callback to our map of callbacks to executors
synchronized (mBluetoothConnectionCallbackExecutorMap) {
+ // If the callback map is empty, we register the service-to-app callback
+ if (mBluetoothConnectionCallbackExecutorMap.isEmpty()) {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null) {
+ if (!mService.registerBluetoothConnectionCallback(mConnectionCallback)) {
+ return false;
+ }
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ mBluetoothConnectionCallbackExecutorMap.remove(callback);
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ // Adds the passed in callback to our map of callbacks to executors
if (mBluetoothConnectionCallbackExecutorMap.containsKey(callback)) {
throw new IllegalArgumentException("This callback has already been registered");
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index ac576a8..abe7fda 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -5989,22 +5989,22 @@
* Creating a window context is an expensive operation. Misuse of this API may lead to a huge
* performance drop. The best practice is to use the same window context when possible.
* An approach is to create one window context with specific window type and display and
- * use it everywhere it's needed..
+ * use it everywhere it's needed.
* </p>
*
* @param type Window type in {@link WindowManager.LayoutParams}
- * @param options Bundle used to pass window-related options.
- * @return A {@link Context} that can be used to create windows.
- * @throws UnsupportedOperationException if this is called on a non-UI context, such as
- * {@link android.app.Application Application} or {@link android.app.Service Service}.
+ * @param options A bundle used to pass window-related options
+ * @return A {@link Context} that can be used to create
+ * non-{@link android.app.Activity activity} windows.
*
* @see #getSystemService(String)
* @see #getSystemService(Class)
* @see #WINDOW_SERVICE
* @see #LAYOUT_INFLATER_SERVICE
* @see #WALLPAPER_SERVICE
- * @throws UnsupportedOperationException if this {@link Context} does not attach to a display or
- * the current number of window contexts without adding any view by
+ * @throws UnsupportedOperationException if this {@link Context} does not attach to a display,
+ * such as {@link android.app.Application Application} or {@link android.app.Service Service},
+ * or the current number of window contexts without adding any view by
* {@link WindowManager#addView} <b>exceeds five</b>.
*/
@UiContext
@@ -6014,6 +6014,32 @@
}
/**
+ * A special version of {@link #createWindowContext(int, Bundle)} which also takes
+ * {@link Display}. The only difference between this API and
+ * {@link #createWindowContext(int, Bundle)} is that this API can create window context from
+ * any context even if the context which is not associated to a {@link Display} instance.
+ *
+ * @param display The {@link Display} to associate with
+ * @param type Window type in {@link WindowManager.LayoutParams}
+ * @param options A bundle used to pass window-related options.
+ * @return A {@link Context} that can be used to create
+ * non-{@link android.app.Activity activity} windows.
+ * @throws IllegalArgumentException if the {@link Display} is {@code null}.
+ *
+ * @see #getSystemService(String)
+ * @see #getSystemService(Class)
+ * @see #WINDOW_SERVICE
+ * @see #LAYOUT_INFLATER_SERVICE
+ * @see #WALLPAPER_SERVICE
+ */
+ @UiContext
+ @NonNull
+ public Context createWindowContext(@NonNull Display display, @WindowType int type,
+ @Nullable Bundle options) {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
* Return a new Context object for the current Context but attribute to a different tag.
* In complex apps attribution tagging can be used to distinguish between separate logical
* parts.
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 56da3cb..e450c08 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -988,6 +988,13 @@
}
@Override
+ @NonNull
+ public Context createWindowContext(@NonNull Display display, @WindowType int type,
+ @Nullable Bundle options) {
+ return mBase.createWindowContext(display, type, options);
+ }
+
+ @Override
public @NonNull Context createAttributionContext(@Nullable String attributionTag) {
return mBase.createAttributionContext(attributionTag);
}
diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java
index f5e1719..2d381eb 100644
--- a/core/java/android/content/res/ApkAssets.java
+++ b/core/java/android/content/res/ApkAssets.java
@@ -25,6 +25,8 @@
import com.android.internal.annotations.GuardedBy;
+import libcore.util.NativeAllocationRegistry;
+
import java.io.FileDescriptor;
import java.io.IOException;
import java.lang.annotation.Retention;
@@ -101,11 +103,11 @@
public @interface FormatType {}
@GuardedBy("this")
- private long mNativePtr; // final, except cleared in finalizer.
+ private final long mNativePtr;
@Nullable
@GuardedBy("this")
- private final StringBlock mStringBlock; // null or closed if mNativePtr = 0.
+ private final StringBlock mStringBlock;
@PropertyFlags
private final int mFlags;
@@ -113,6 +115,19 @@
@Nullable
private final AssetsProvider mAssets;
+ @GuardedBy("this")
+ @Nullable
+ private final Runnable mRunNativeCleanup;
+
+ // Use a Holder to allow static initialization of ApkAssets in the boot image, and
+ // possibly to avoid some initialization ordering issues.
+ private static class NoImagePreloadHolder {
+ // TODO(175425996): Make size estimate more accurate
+ public static final NativeAllocationRegistry REGISTRY =
+ NativeAllocationRegistry.createMalloced(ApkAssets.class.getClassLoader(),
+ nativeGetFinalizer());
+ }
+
/**
* Creates a new ApkAssets instance from the given path on disk.
*
@@ -287,6 +302,8 @@
mFlags = flags;
mNativePtr = nativeLoad(format, path, flags, assets);
mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/);
+ mRunNativeCleanup = NoImagePreloadHolder.REGISTRY.registerNativeAllocation(
+ this, mNativePtr);
mAssets = assets;
}
@@ -298,6 +315,8 @@
mFlags = flags;
mNativePtr = nativeLoadFd(format, fd, friendlyName, flags, assets);
mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/);
+ mRunNativeCleanup = NoImagePreloadHolder.REGISTRY.registerNativeAllocation(
+ this, mNativePtr);
mAssets = assets;
}
@@ -309,6 +328,8 @@
mFlags = flags;
mNativePtr = nativeLoadFdOffsets(format, fd, friendlyName, offset, length, flags, assets);
mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/);
+ mRunNativeCleanup = NoImagePreloadHolder.REGISTRY.registerNativeAllocation(
+ this, mNativePtr);
mAssets = assets;
}
@@ -316,6 +337,7 @@
mFlags = flags;
mNativePtr = nativeLoadEmpty(flags, assets);
mStringBlock = null;
+ mRunNativeCleanup = null;
mAssets = assets;
}
@@ -403,22 +425,16 @@
return "ApkAssets{path=" + getAssetPath() + "}";
}
- @Override
- protected void finalize() throws Throwable {
- close();
- }
-
/**
* Closes this class and the contained {@link #mStringBlock}.
*/
public void close() {
synchronized (this) {
- if (mNativePtr != 0) {
- if (mStringBlock != null) {
- mStringBlock.close();
- }
- nativeDestroy(mNativePtr);
- mNativePtr = 0;
+ if (mStringBlock != null) {
+ mStringBlock.close();
+ }
+ if (mRunNativeCleanup != null) {
+ mRunNativeCleanup.run();
}
}
}
@@ -433,7 +449,6 @@
private static native long nativeLoadFdOffsets(@FormatType int format,
@NonNull FileDescriptor fd, @NonNull String friendlyName, long offset, long length,
@PropertyFlags int flags, @Nullable AssetsProvider asset) throws IOException;
- private static native void nativeDestroy(long ptr);
private static native @NonNull String nativeGetAssetPath(long ptr);
private static native long nativeGetStringBlock(long ptr);
private static native boolean nativeIsUpToDate(long ptr);
@@ -441,4 +456,5 @@
private static native @Nullable OverlayableInfo nativeGetOverlayableInfo(long ptr,
String overlayableName) throws IOException;
private static native boolean nativeDefinesOverlayable(long ptr) throws IOException;
+ private static native final long nativeGetFinalizer();
}
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index e913986..f7c4c2c 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -19,6 +19,7 @@
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
+import android.hardware.input.InputSensorInfo;
import android.os.Build;
/**
@@ -923,6 +924,30 @@
}
/**
+ * Construct a sensor object from SensorInfo of an input device.
+ * This is only used for constructing an input device sensor object.
+ * @hide
+ */
+ public Sensor(InputSensorInfo sensorInfo) {
+ this.mName = sensorInfo.getName();
+ this.mVendor = sensorInfo.getVendor();
+ this.mVersion = sensorInfo.getVersion();
+ this.mHandle = sensorInfo.getHandle();
+ this.mType = sensorInfo.getType();
+ this.mMaxRange = sensorInfo.getMaxRange();
+ this.mResolution = sensorInfo.getResolution();
+ this.mPower = sensorInfo.getPower();
+ this.mMinDelay = sensorInfo.getMinDelay();
+ this.mFifoReservedEventCount = sensorInfo.getFifoReservedEventCount();
+ this.mFifoMaxEventCount = sensorInfo.getFifoMaxEventCount();
+ this.mStringType = sensorInfo.getStringType();
+ this.mRequiredPermission = sensorInfo.getRequiredPermission();
+ this.mMaxDelay = sensorInfo.getMaxDelay();
+ this.mFlags = sensorInfo.getFlags();
+ this.mId = sensorInfo.getId();
+ }
+
+ /**
* @return name string of the sensor.
*/
public String getName() {
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 236fab0..232f234 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -16,6 +16,7 @@
package android.hardware;
+import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
/**
@@ -667,4 +668,16 @@
SensorEvent(int valueSize) {
values = new float[valueSize];
}
+
+ /**
+ * Construct a sensor event object by sensor object, accuracy, timestamp and values.
+ * This is only used for constructing an input device sensor event object.
+ * @hide
+ */
+ public SensorEvent(@NonNull Sensor sensor, int accuracy, long timestamp, float[] values) {
+ this.sensor = sensor;
+ this.accuracy = accuracy;
+ this.timestamp = timestamp;
+ this.values = values;
+ }
}
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 3a73de6..43f04cd 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -848,6 +848,20 @@
}
/**
+ * Determines whether the HDMI CEC stack should handle KEYCODE_TV_POWER.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.HDMI_CEC)
+ public boolean shouldHandleTvPowerKey() {
+ try {
+ return mService.shouldHandleTvPowerKey();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Controls whether volume control commands via HDMI CEC are enabled.
*
* <p>When disabled:
diff --git a/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java b/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java
index 202e090..3b61911f 100644
--- a/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java
+++ b/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java
@@ -72,6 +72,11 @@
}
@Override
+ public boolean shouldHandleTvPowerKey() {
+ return HdmiControlServiceWrapper.this.shouldHandleTvPowerKey();
+ }
+
+ @Override
public void queryDisplayStatus(IHdmiControlCallback callback) {
HdmiControlServiceWrapper.this.queryDisplayStatus(callback);
}
@@ -368,6 +373,11 @@
public void toggleAndFollowTvPower() {}
/** @hide */
+ public boolean shouldHandleTvPowerKey() {
+ return true;
+ }
+
+ /** @hide */
public void queryDisplayStatus(IHdmiControlCallback callback) {}
/** @hide */
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 6d0c688..65bd856 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -43,6 +43,7 @@
HdmiDeviceInfo getActiveSource();
void oneTouchPlay(IHdmiControlCallback callback);
void toggleAndFollowTvPower();
+ boolean shouldHandleTvPowerKey();
void queryDisplayStatus(IHdmiControlCallback callback);
void addHdmiControlStatusChangeListener(IHdmiControlStatusChangeListener listener);
void removeHdmiControlStatusChangeListener(IHdmiControlStatusChangeListener listener);
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 3f3c3bf..b39df4d 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -23,6 +23,8 @@
import android.hardware.input.ITabletModeChangedListener;
import android.hardware.input.TouchCalibration;
import android.os.CombinedVibrationEffect;
+import android.hardware.input.IInputSensorEventListener;
+import android.hardware.input.InputSensorInfo;
import android.os.IBinder;
import android.os.VibrationEffect;
import android.view.InputDevice;
@@ -105,4 +107,17 @@
// Remove the runtime association between the input port and the display port. Any existing
// static association for the cleared input port will be restored.
void removePortAssociation(in String inputPort);
+
+ InputSensorInfo[] getSensorList(int deviceId);
+
+ boolean registerSensorListener(IInputSensorEventListener listener);
+
+ void unregisterSensorListener(IInputSensorEventListener listener);
+
+ boolean enableSensor(int deviceId, int sensorType, int samplingPeriodUs,
+ int maxBatchReportLatencyUs);
+
+ void disableSensor(int deviceId, int sensorType);
+
+ boolean flushSensor(int deviceId, int sensorType);
}
diff --git a/core/java/android/hardware/input/IInputSensorEventListener.aidl b/core/java/android/hardware/input/IInputSensorEventListener.aidl
new file mode 100644
index 0000000..508f590
--- /dev/null
+++ b/core/java/android/hardware/input/IInputSensorEventListener.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.input;
+
+/** @hide */
+interface IInputSensorEventListener {
+ /* Called when there is a new sensor event. */
+ oneway void onInputSensorChanged(int deviceId, int sensorId, int accuracy, long timestamp,
+ in float[] values);
+
+ /* Called when the accuracy of the registered sensor has changed. */
+ oneway void onInputSensorAccuracyChanged(int deviceId, int sensorId, int accuracy);
+}
diff --git a/core/java/android/hardware/input/InputDeviceSensorManager.java b/core/java/android/hardware/input/InputDeviceSensorManager.java
new file mode 100644
index 0000000..56c2cdd
--- /dev/null
+++ b/core/java/android/hardware/input/InputDeviceSensorManager.java
@@ -0,0 +1,661 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.input;
+
+import android.annotation.NonNull;
+import android.hardware.HardwareBuffer;
+import android.hardware.Sensor;
+import android.hardware.SensorAdditionalInfo;
+import android.hardware.SensorDirectChannel;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.hardware.TriggerEventListener;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.MemoryFile;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.InputDevice;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.SomeArgs;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Sensor manager implementation that communicates with the input device
+ * sensors.
+ * @hide
+ */
+public class InputDeviceSensorManager implements InputManager.InputDeviceListener {
+ private static final String TAG = "InputDeviceSensorManager";
+ private static final boolean DEBUG = false;
+
+ private static final int MSG_SENSOR_ACCURACY_CHANGED = 1;
+ private static final int MSG_SENSOR_CHANGED = 2;
+
+ private InputManager mInputManager;
+
+ // sensor map from device id to sensor list
+ @GuardedBy("mInputSensorLock")
+ private final Map<Integer, List<Sensor>> mSensors = new HashMap<>();
+
+ private final Object mInputSensorLock = new Object();
+ private InputSensorEventListener mInputServiceSensorListener;
+ @GuardedBy("mInputSensorLock")
+ private final ArrayList<InputSensorEventListenerDelegate> mInputSensorEventListeners =
+ new ArrayList<InputSensorEventListenerDelegate>();
+ private HandlerThread mSensorThread = null;
+ private Handler mSensorHandler = null;
+
+ public InputDeviceSensorManager(InputManager inputManager) {
+ mInputManager = inputManager;
+
+ mSensorThread = new HandlerThread("SensorThread");
+ mSensorThread.start();
+ mSensorHandler = new Handler(mSensorThread.getLooper());
+
+ // Register the input device listener
+ mInputManager.registerInputDeviceListener(this, mSensorHandler);
+ // Initialize the sensor list
+ initializeSensors();
+ }
+
+ /*
+ * Get SensorManager object for specific input device
+ *
+ * @param deviceId Input device ID
+ * @return SensorManager object for input device
+ */
+ SensorManager getSensorManager(int deviceId) {
+ return new InputSensorManager(deviceId);
+ }
+
+ /*
+ * Update input device sensor info for specified input device ID.
+ */
+ private void updateInputDeviceSensorInfoLocked(int deviceId) {
+ final InputDevice inputDevice = InputDevice.getDevice(deviceId);
+ if (inputDevice.hasSensor()) {
+ final InputSensorInfo[] sensorInfos =
+ mInputManager.getSensorList(deviceId);
+ populateSensorsForInputDeviceLocked(deviceId, sensorInfos);
+ }
+ }
+
+ @Override
+ public void onInputDeviceAdded(int deviceId) {
+ synchronized (mInputSensorLock) {
+ if (!mSensors.containsKey(deviceId)) {
+ updateInputDeviceSensorInfoLocked(deviceId);
+ } else {
+ Slog.e(TAG, "Received 'device added' notification for device " + deviceId
+ + ", but it is already in the list");
+ }
+ }
+ }
+
+ @Override
+ public void onInputDeviceRemoved(int deviceId) {
+ synchronized (mInputSensorLock) {
+ mSensors.remove(deviceId);
+ }
+ }
+
+ @Override
+ public void onInputDeviceChanged(int deviceId) {
+ synchronized (mInputSensorLock) {
+ if (mSensors.containsKey(deviceId)) {
+ mSensors.remove(deviceId);
+ }
+ updateInputDeviceSensorInfoLocked(deviceId);
+ }
+ }
+
+ private static boolean sensorEquals(@NonNull Sensor lhs, @NonNull Sensor rhs) {
+ if (lhs.getType() == rhs.getType() && lhs.getId() == rhs.getId()) {
+ return true;
+ }
+ return false;
+ }
+
+ private void populateSensorsForInputDeviceLocked(int deviceId, InputSensorInfo[] sensorInfos) {
+ List<Sensor> sensors = new ArrayList<Sensor>();
+ for (int i = 0; i < sensorInfos.length; i++) {
+ Sensor sensor = new Sensor(sensorInfos[i]);
+ if (DEBUG) {
+ Slog.d(TAG, "Device " + deviceId + " sensor " + sensor.getStringType() + " added");
+ }
+ sensors.add(sensor);
+ }
+ mSensors.put(deviceId, sensors);
+ }
+
+ private void initializeSensors() {
+ synchronized (mInputSensorLock) {
+ mSensors.clear();
+ int[] deviceIds = mInputManager.getInputDeviceIds();
+ for (int i = 0; i < deviceIds.length; i++) {
+ final int deviceId = deviceIds[i];
+ updateInputDeviceSensorInfoLocked(deviceId);
+ }
+ }
+ }
+
+ /**
+ * Get a sensor object for input device, with specific sensor type.
+ * @param deviceId The input devicd ID
+ * @param sensorType The sensor type
+ * @return The sensor object if exists or null
+ */
+ @GuardedBy("mInputSensorLock")
+ private Sensor getInputDeviceSensorLocked(int deviceId, int sensorType) {
+ List<Sensor> sensors = mSensors.get(deviceId);
+ for (Sensor sensor : sensors) {
+ if (sensor.getType() == sensorType) {
+ return sensor;
+ }
+ }
+ return null;
+ }
+
+ @GuardedBy("mInputSensorLock")
+ private int findSensorEventListenerLocked(SensorEventListener listener) {
+ for (int i = 0; i < mInputSensorEventListeners.size(); i++) {
+ if (mInputSensorEventListeners.get(i).getListener() == listener) {
+ return i;
+ }
+ }
+ return Integer.MIN_VALUE;
+ }
+
+ private void onInputSensorChanged(int deviceId, int sensorType, int accuracy, long timestamp,
+ float[] values) {
+ if (DEBUG) {
+ Slog.d(TAG, "Sensor changed: deviceId =" + deviceId
+ + " timestamp=" + timestamp + " sensorType=" + sensorType);
+ }
+ synchronized (mInputSensorLock) {
+ SensorEvent event = createSensorEvent(
+ InputDevice.getDevice(deviceId), sensorType, accuracy, timestamp, values);
+ if (event == null) {
+ Slog.wtf(TAG, "Failed to create SensorEvent.");
+ return;
+ }
+ for (int i = 0; i < mInputSensorEventListeners.size(); i++) {
+ InputSensorEventListenerDelegate listener =
+ mInputSensorEventListeners.get(i);
+ if (listener.hasSensorRegistered(deviceId, sensorType)) {
+ listener.sendSensorChanged(event);
+ }
+ }
+ }
+ }
+
+ private void onInputSensorAccuracyChanged(int deviceId, int sensorType, int accuracy) {
+ if (DEBUG) {
+ Slog.d(TAG, "Sensor accuracy changed: "
+ + "accuracy=" + accuracy + ", sensorType=" + sensorType);
+ }
+ synchronized (mInputSensorLock) {
+ for (int i = 0; i < mInputSensorEventListeners.size(); i++) {
+ InputSensorEventListenerDelegate listener =
+ mInputSensorEventListeners.get(i);
+ if (listener.hasSensorRegistered(deviceId, sensorType)) {
+ listener.sendSensorAccuracyChanged(deviceId, sensorType, accuracy);
+ }
+ }
+ }
+ }
+
+ private final class InputSensorEventListener extends IInputSensorEventListener.Stub {
+ @Override
+ public void onInputSensorChanged(int deviceId, int sensorType, int accuracy, long timestamp,
+ float[] values) throws RemoteException {
+ InputDeviceSensorManager.this.onInputSensorChanged(
+ deviceId, sensorType, accuracy, timestamp, values);
+ }
+
+ @Override
+ public void onInputSensorAccuracyChanged(int deviceId, int sensorType, int accuracy)
+ throws RemoteException {
+ InputDeviceSensorManager.this.onInputSensorAccuracyChanged(deviceId, sensorType,
+ accuracy);
+ }
+
+ }
+
+ private static final class InputSensorEventListenerDelegate extends Handler {
+ private final SensorEventListener mListener;
+ private final int mDelayUs;
+ private final int mMaxBatchReportLatencyUs;
+ private List<Sensor> mSensors = new ArrayList<Sensor>();
+
+ InputSensorEventListenerDelegate(SensorEventListener listener, Sensor sensor,
+ int delayUs, int maxBatchReportLatencyUs, Handler handler) {
+ super(handler != null ? handler.getLooper() : Looper.myLooper());
+ mListener = listener;
+ mSensors.add(sensor);
+ mDelayUs = delayUs;
+ mMaxBatchReportLatencyUs = maxBatchReportLatencyUs;
+ }
+
+ public List<Sensor> getSensors() {
+ return mSensors;
+ }
+
+ public boolean isEmpty() {
+ return mSensors.isEmpty();
+ }
+
+ /**
+ * Remove sensor from sensor list for listener
+ */
+ public void removeSensor(Sensor sensor) {
+ // If sensor is not specified the listener will be unregistered for all sensors
+ // and the sensor list is cleared.
+ if (sensor == null) {
+ mSensors.clear();
+ }
+ for (Sensor s : mSensors) {
+ if (sensorEquals(s, sensor)) {
+ mSensors.remove(sensor);
+ }
+ }
+ }
+
+ /**
+ * Add a sensor to listener's sensor list
+ */
+ public void addSensor(@NonNull Sensor sensor) {
+ for (Sensor s : mSensors) {
+ if (sensorEquals(s, sensor)) {
+ Slog.w(TAG, "Adding sensor " + sensor + " already exist!");
+ return;
+ }
+ }
+ mSensors.add(sensor);
+ }
+
+ /**
+ * Check if the listener has been registered to the sensor
+ * @param deviceId The input device ID of the sensor
+ * @param sensorType The sensor type of the sensor
+ * @return true if specified sensor is registered for the listener.
+ */
+ public boolean hasSensorRegistered(int deviceId, int sensorType) {
+ for (Sensor sensor : mSensors) {
+ if (sensor.getType() == sensorType && sensor.getId() == deviceId) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get listener handle for the delegate
+ */
+ public SensorEventListener getListener() {
+ return mListener;
+ }
+
+ /**
+ * Send sensor changed message
+ */
+ public void sendSensorChanged(SensorEvent event) {
+ SomeArgs args = SomeArgs.obtain();
+ obtainMessage(MSG_SENSOR_CHANGED, event).sendToTarget();
+ }
+
+ /**
+ * Send sensor accuracy changed message
+ */
+ public void sendSensorAccuracyChanged(int deviceId, int sensorType, int accuracy) {
+ SomeArgs args = SomeArgs.obtain();
+ obtainMessage(MSG_SENSOR_ACCURACY_CHANGED, deviceId, sensorType, accuracy)
+ .sendToTarget();
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SENSOR_ACCURACY_CHANGED: {
+ final int deviceId = msg.arg1;
+ final int sensorType = msg.arg2;
+ final int accuracy = (int) msg.obj;
+ for (Sensor sensor : mSensors) {
+ if (sensor.getId() == deviceId && sensor.getType() == sensorType) {
+ mListener.onAccuracyChanged(sensor, accuracy);
+ }
+ }
+ break;
+ }
+ case MSG_SENSOR_CHANGED: {
+ SensorEvent event = (SensorEvent) msg.obj;
+ mListener.onSensorChanged(event);
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Create SensorEvent object for input device, with specified device ID, sensor Type,
+ * sensor event timestamp, accuracy, and sensor values.
+ */
+ private SensorEvent createSensorEvent(InputDevice inputDevice, int sensorType, int accuracy,
+ long timestamp, float[] values) {
+ synchronized (mInputSensorLock) {
+ Sensor sensor = getInputDeviceSensorLocked(inputDevice.getId(), sensorType);
+ if (sensor == null) {
+ Slog.wtf(TAG, "Can't get sensor type " + sensorType + " for input device "
+ + inputDevice);
+ }
+ SensorEvent event = new SensorEvent(sensor, accuracy, timestamp, values);
+ if (event == null) {
+ Slog.wtf(TAG, "Failed to create SensorEvent.");
+ }
+ return event;
+ }
+ }
+
+ /**
+ * Return the default sensor object for input device, for specific sensor type.
+ */
+ private Sensor getSensorForInputDevice(int deviceId, int type) {
+ synchronized (mInputSensorLock) {
+ for (Map.Entry<Integer, List<Sensor>> entry : mSensors.entrySet()) {
+ for (Sensor sensor : entry.getValue()) {
+ if (sensor.getId() == deviceId && sensor.getType() == type) {
+ if (DEBUG) {
+ Slog.d(TAG, "Device " + deviceId + " sensor " + sensor.getStringType());
+ }
+ return sensor;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return list of sensors that belong to an input device, specified by input device ID.
+ */
+ private List<Sensor> getFullSensorListForDevice(int deviceId) {
+ List<Sensor> sensors = new ArrayList<Sensor>();
+ synchronized (mInputSensorLock) {
+ for (Map.Entry<Integer, List<Sensor>> entry : mSensors.entrySet()) {
+ for (Sensor sensor : entry.getValue()) {
+ if (sensor.getId() == deviceId) {
+ if (DEBUG) {
+ Slog.d(TAG, "Device " + deviceId + " sensor " + sensor.getStringType());
+ }
+ sensors.add(sensor);
+ }
+ }
+ }
+ }
+ return sensors;
+ }
+
+ private boolean registerListenerInternal(SensorEventListener listener, Sensor sensor,
+ int delayUs, int maxBatchReportLatencyUs, Handler handler) {
+ if (DEBUG) {
+ Slog.d(TAG, "registerListenerImpl listener=" + listener + " sensor=" + sensor
+ + " delayUs=" + delayUs
+ + " maxBatchReportLatencyUs=" + maxBatchReportLatencyUs);
+ }
+ if (listener == null) {
+ Slog.e(TAG, "listener is null");
+ return false;
+ }
+
+ if (sensor == null) {
+ Slog.e(TAG, "sensor is null");
+ return false;
+ }
+
+ // Trigger Sensors should use the requestTriggerSensor call.
+ if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
+ Slog.e(TAG, "Trigger Sensors should use the requestTriggerSensor.");
+ return false;
+ }
+ if (maxBatchReportLatencyUs < 0 || delayUs < 0) {
+ Slog.e(TAG, "maxBatchReportLatencyUs and delayUs should be non-negative");
+ return false;
+ }
+
+ if (getSensorForInputDevice(sensor.getId(), sensor.getType()) != null) {
+ synchronized (mInputSensorLock) {
+ final int deviceId = sensor.getId();
+ InputDevice inputDevice = InputDevice.getDevice(deviceId);
+ if (!inputDevice.hasSensor()) {
+ Slog.e(TAG, "The device doesn't have the sensor:" + sensor);
+ return false;
+ }
+ if (!mInputManager.enableSensor(deviceId, sensor.getType(), delayUs,
+ maxBatchReportLatencyUs)) {
+ Slog.e(TAG, "Can't enable the sensor:" + sensor);
+ return false;
+ }
+ }
+ }
+
+ synchronized (mInputSensorLock) {
+ // Register the InputManagerService sensor listener if not yet.
+ if (mInputServiceSensorListener == null) {
+ mInputServiceSensorListener = new InputSensorEventListener();
+ if (!mInputManager.registerSensorListener(mInputServiceSensorListener)) {
+ Slog.e(TAG, "Failed registering the sensor listener");
+ return false;
+ }
+ }
+
+ int idx = findSensorEventListenerLocked(listener);
+ if (idx < 0) {
+ InputSensorEventListenerDelegate d =
+ new InputSensorEventListenerDelegate(listener, sensor, delayUs,
+ maxBatchReportLatencyUs,
+ handler == null ? mSensorHandler : handler);
+ mInputSensorEventListeners.add(d);
+ } else {
+ // The listener is already registered, see if it wants to listen to more sensors.
+ mInputSensorEventListeners.get(idx).addSensor(sensor);
+ }
+ }
+
+ return true;
+ }
+
+ private void unregisterListenerInternal(SensorEventListener listener, Sensor sensor) {
+ if (DEBUG) {
+ Slog.d(TAG, "unregisterListenerImpl listener=" + listener + " sensor=" + sensor);
+ }
+ if (listener == null) { // it's OK for the sensor to be null
+ throw new IllegalArgumentException("listener must not be null");
+ }
+ synchronized (mInputSensorLock) {
+ int idx = findSensorEventListenerLocked(listener);
+ // Track the sensor types and the device Id the listener has registered.
+ final List<Sensor> sensorsRegistered;
+ if (idx >= 0) {
+ InputSensorEventListenerDelegate delegate =
+ mInputSensorEventListeners.get(idx);
+ sensorsRegistered = new ArrayList<Sensor>(delegate.getSensors());
+ // Get the sensor types the listener is listening to
+ delegate.removeSensor(sensor);
+ if (delegate.isEmpty()) {
+ // If no sensors to listen, remove the listener delegate
+ mInputSensorEventListeners.remove(idx);
+ }
+ } else {
+ Slog.e(TAG, "Listener is not registered");
+ return;
+ }
+ // If no delegation remains, unregister the listener to input service
+ if (mInputServiceSensorListener != null && mInputSensorEventListeners.size() == 0) {
+ mInputManager.unregisterSensorListener(mInputServiceSensorListener);
+ mInputServiceSensorListener = null;
+ }
+ // For each sensor type check if it is still in use by other listeners.
+ for (Sensor s : sensorsRegistered) {
+ final int deviceId = s.getId();
+ final int sensorType = s.getType();
+ // See if we can disable the sensor
+ boolean enableSensor = false;
+ for (int i = 0; i < mInputSensorEventListeners.size(); i++) {
+ InputSensorEventListenerDelegate delegate =
+ mInputSensorEventListeners.get(i);
+ if (delegate.hasSensorRegistered(deviceId, sensorType)) {
+ enableSensor = true;
+ Slog.w(TAG, "device " + deviceId + " still uses sensor " + sensorType);
+ break;
+ }
+ }
+ // Sensor is not listened, disable it.
+ if (!enableSensor) {
+ if (DEBUG) {
+ Slog.d(TAG, "device " + deviceId + " sensor " + sensorType + " disabled");
+ }
+ mInputManager.disableSensor(deviceId, sensorType);
+ }
+ }
+ }
+ }
+
+ private boolean flush(SensorEventListener listener) {
+ synchronized (mInputSensorLock) {
+ int idx = findSensorEventListenerLocked(listener);
+ if (idx < 0) {
+ return false;
+ }
+ for (Sensor sensor : mInputSensorEventListeners.get(idx).getSensors()) {
+ final int deviceId = sensor.getId();
+ if (!mInputManager.flushSensor(deviceId, sensor.getType())) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ /**
+ * Sensor Manager class associated with specific input device
+ */
+ public class InputSensorManager extends SensorManager {
+ // Input device ID that the sensors belong to
+ final int mId;
+
+ InputSensorManager(int deviceId) {
+ mId = deviceId;
+ }
+
+ @Override
+ public Sensor getDefaultSensor(int type) {
+ return getSensorForInputDevice(mId, type);
+ }
+
+ @Override
+ protected List<Sensor> getFullSensorList() {
+ return getFullSensorListForDevice(mId);
+ }
+
+ @Override
+ protected List<Sensor> getFullDynamicSensorList() {
+ return new ArrayList<>();
+ }
+
+ @Override
+ protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
+ int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags) {
+ return registerListenerInternal(listener, sensor, delayUs,
+ maxBatchReportLatencyUs, handler);
+ }
+
+ @Override
+ protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
+ unregisterListenerInternal(listener, sensor);
+ }
+
+ @Override
+ protected boolean flushImpl(SensorEventListener listener) {
+ return flush(listener);
+ }
+
+ @Override
+ protected SensorDirectChannel createDirectChannelImpl(MemoryFile memoryFile,
+ HardwareBuffer hardwareBuffer) {
+ return null;
+ }
+
+ @Override
+ protected void destroyDirectChannelImpl(SensorDirectChannel channel) {
+
+ }
+
+ @Override
+ protected int configureDirectChannelImpl(SensorDirectChannel channel, Sensor s, int rate) {
+ return 0;
+ }
+
+ @Override
+ protected void registerDynamicSensorCallbackImpl(DynamicSensorCallback callback,
+ Handler handler) {
+
+ }
+
+ @Override
+ protected void unregisterDynamicSensorCallbackImpl(
+ DynamicSensorCallback callback) {
+
+ }
+
+ @Override
+ protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) {
+ return true;
+ }
+
+ @Override
+ protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor,
+ boolean disable) {
+ return true;
+ }
+
+ @Override
+ protected boolean initDataInjectionImpl(boolean enable) {
+ return false;
+ }
+
+ @Override
+ protected boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy,
+ long timestamp) {
+ return false;
+ }
+
+ @Override
+ protected boolean setOperationParameterImpl(SensorAdditionalInfo parameter) {
+ return false;
+ }
+ }
+
+}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index dd71cce..300d99b 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -28,6 +28,7 @@
import android.compat.annotation.ChangeId;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
+import android.hardware.SensorManager;
import android.os.BlockUntrustedTouchesMode;
import android.os.Build;
import android.os.CombinedVibrationEffect;
@@ -100,6 +101,7 @@
private TabletModeChangedListener mTabletModeChangedListener;
private List<OnTabletModeChangedListenerDelegate> mOnTabletModeChangedListeners;
+ private InputDeviceSensorManager mInputDeviceSensorManager;
/**
* Broadcast Action: Query available keyboard layouts.
* <p>
@@ -193,7 +195,7 @@
*/
@BlockUntrustedTouchesMode
public static final int DEFAULT_BLOCK_UNTRUSTED_TOUCHES_MODE =
- BlockUntrustedTouchesMode.BLOCK;
+ BlockUntrustedTouchesMode.PERMISSIVE;
/**
* Prevent touches from being consumed by apps if these touches passed through a non-trusted
@@ -291,6 +293,18 @@
}
/**
+ * Clear the instance of the input manager.
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ public static void clearInstance() {
+ synchronized (InputManager.class) {
+ sInstance = null;
+ }
+ }
+
+ /**
* Gets an instance of the input manager.
*
* @return The input manager instance.
@@ -1152,6 +1166,86 @@
}
/**
+ * Get sensors information as list.
+ *
+ * @hide
+ */
+ public InputSensorInfo[] getSensorList(int deviceId) {
+ try {
+ return mIm.getSensorList(deviceId);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Enable input device sensor
+ *
+ * @hide
+ */
+ public boolean enableSensor(int deviceId, int sensorType, int samplingPeriodUs,
+ int maxBatchReportLatencyUs) {
+ try {
+ return mIm.enableSensor(deviceId, sensorType, samplingPeriodUs,
+ maxBatchReportLatencyUs);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Enable input device sensor
+ *
+ * @hide
+ */
+ public void disableSensor(int deviceId, int sensorType) {
+ try {
+ mIm.disableSensor(deviceId, sensorType);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Flush input device sensor
+ *
+ * @hide
+ */
+ public boolean flushSensor(int deviceId, int sensorType) {
+ try {
+ return mIm.flushSensor(deviceId, sensorType);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Register input device sensor listener
+ *
+ * @hide
+ */
+ public boolean registerSensorListener(IInputSensorEventListener listener) {
+ try {
+ return mIm.registerSensorListener(listener);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Unregister input device sensor listener
+ *
+ * @hide
+ */
+ public void unregisterSensorListener(IInputSensorEventListener listener) {
+ try {
+ mIm.unregisterSensorListener(listener);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Add a runtime association between the input port and the display port. This overrides any
* static associations.
* @param inputPort The port of the input device.
@@ -1289,7 +1383,7 @@
}
/**
- * Gets a vibrator service associated with an input device, assuming it has one.
+ * Gets a vibrator service associated with an input device, always create a new instance.
* @return The vibrator, never null.
* @hide
*/
@@ -1365,6 +1459,19 @@
}
/**
+ * Gets a sensor manager service associated with an input device, always create a new instance.
+ * @return The sensor manager, never null.
+ * @hide
+ */
+ @NonNull
+ public SensorManager getInputDeviceSensorManager(int deviceId) {
+ if (mInputDeviceSensorManager == null) {
+ mInputDeviceSensorManager = new InputDeviceSensorManager(this);
+ }
+ return mInputDeviceSensorManager.getSensorManager(deviceId);
+ }
+
+ /**
* Listens for changes in input devices.
*/
public interface InputDeviceListener {
diff --git a/core/java/android/hardware/input/InputSensorInfo.aidl b/core/java/android/hardware/input/InputSensorInfo.aidl
new file mode 100644
index 0000000..d9a604a
--- /dev/null
+++ b/core/java/android/hardware/input/InputSensorInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.input;
+
+parcelable InputSensorInfo;
diff --git a/core/java/android/hardware/input/InputSensorInfo.java b/core/java/android/hardware/input/InputSensorInfo.java
new file mode 100644
index 0000000..99b1879
--- /dev/null
+++ b/core/java/android/hardware/input/InputSensorInfo.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.input;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+/**
+ * This class represents a motion sensor for input devices.
+ *
+ * @hide
+ */
+@DataClass(
+ genToString = true,
+ genHiddenConstructor = true,
+ genHiddenConstDefs = true)
+public class InputSensorInfo implements Parcelable {
+
+ private @NonNull String mName;
+ private @NonNull String mVendor;
+ private int mVersion;
+ private int mHandle;
+ private int mType;
+ private float mMaxRange;
+ private float mResolution;
+ private float mPower;
+ private int mMinDelay;
+ private int mFifoReservedEventCount;
+ private int mFifoMaxEventCount;
+ private @NonNull String mStringType;
+ private @NonNull String mRequiredPermission;
+ private int mMaxDelay;
+ private int mFlags;
+ private int mId;
+
+
+
+ // Code below generated by codegen v1.0.20.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/hardware/input/InputSensorInfo.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /**
+ * Creates a new InputSensorInfo.
+ *
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public InputSensorInfo(
+ @NonNull String name,
+ @NonNull String vendor,
+ int version,
+ int handle,
+ int type,
+ float maxRange,
+ float resolution,
+ float power,
+ int minDelay,
+ int fifoReservedEventCount,
+ int fifoMaxEventCount,
+ @NonNull String stringType,
+ @NonNull String requiredPermission,
+ int maxDelay,
+ int flags,
+ int id) {
+ this.mName = name;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mName);
+ this.mVendor = vendor;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mVendor);
+ this.mVersion = version;
+ this.mHandle = handle;
+ this.mType = type;
+ this.mMaxRange = maxRange;
+ this.mResolution = resolution;
+ this.mPower = power;
+ this.mMinDelay = minDelay;
+ this.mFifoReservedEventCount = fifoReservedEventCount;
+ this.mFifoMaxEventCount = fifoMaxEventCount;
+ this.mStringType = stringType;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mStringType);
+ this.mRequiredPermission = requiredPermission;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mRequiredPermission);
+ this.mMaxDelay = maxDelay;
+ this.mFlags = flags;
+ this.mId = id;
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull String getName() {
+ return mName;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull String getVendor() {
+ return mVendor;
+ }
+
+ @DataClass.Generated.Member
+ public int getVersion() {
+ return mVersion;
+ }
+
+ @DataClass.Generated.Member
+ public int getHandle() {
+ return mHandle;
+ }
+
+ @DataClass.Generated.Member
+ public int getType() {
+ return mType;
+ }
+
+ @DataClass.Generated.Member
+ public float getMaxRange() {
+ return mMaxRange;
+ }
+
+ @DataClass.Generated.Member
+ public float getResolution() {
+ return mResolution;
+ }
+
+ @DataClass.Generated.Member
+ public float getPower() {
+ return mPower;
+ }
+
+ @DataClass.Generated.Member
+ public int getMinDelay() {
+ return mMinDelay;
+ }
+
+ @DataClass.Generated.Member
+ public int getFifoReservedEventCount() {
+ return mFifoReservedEventCount;
+ }
+
+ @DataClass.Generated.Member
+ public int getFifoMaxEventCount() {
+ return mFifoMaxEventCount;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull String getStringType() {
+ return mStringType;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull String getRequiredPermission() {
+ return mRequiredPermission;
+ }
+
+ @DataClass.Generated.Member
+ public int getMaxDelay() {
+ return mMaxDelay;
+ }
+
+ @DataClass.Generated.Member
+ public int getFlags() {
+ return mFlags;
+ }
+
+ @DataClass.Generated.Member
+ public int getId() {
+ return mId;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public String toString() {
+ // You can override field toString logic by defining methods like:
+ // String fieldNameToString() { ... }
+
+ return "InputSensorInfo { " +
+ "name = " + mName + ", " +
+ "vendor = " + mVendor + ", " +
+ "version = " + mVersion + ", " +
+ "handle = " + mHandle + ", " +
+ "type = " + mType + ", " +
+ "maxRange = " + mMaxRange + ", " +
+ "resolution = " + mResolution + ", " +
+ "power = " + mPower + ", " +
+ "minDelay = " + mMinDelay + ", " +
+ "fifoReservedEventCount = " + mFifoReservedEventCount + ", " +
+ "fifoMaxEventCount = " + mFifoMaxEventCount + ", " +
+ "stringType = " + mStringType + ", " +
+ "requiredPermission = " + mRequiredPermission + ", " +
+ "maxDelay = " + mMaxDelay + ", " +
+ "flags = " + mFlags + ", " +
+ "id = " + mId +
+ " }";
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ dest.writeString(mName);
+ dest.writeString(mVendor);
+ dest.writeInt(mVersion);
+ dest.writeInt(mHandle);
+ dest.writeInt(mType);
+ dest.writeFloat(mMaxRange);
+ dest.writeFloat(mResolution);
+ dest.writeFloat(mPower);
+ dest.writeInt(mMinDelay);
+ dest.writeInt(mFifoReservedEventCount);
+ dest.writeInt(mFifoMaxEventCount);
+ dest.writeString(mStringType);
+ dest.writeString(mRequiredPermission);
+ dest.writeInt(mMaxDelay);
+ dest.writeInt(mFlags);
+ dest.writeInt(mId);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ protected InputSensorInfo(@NonNull Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ String name = in.readString();
+ String vendor = in.readString();
+ int version = in.readInt();
+ int handle = in.readInt();
+ int type = in.readInt();
+ float maxRange = in.readFloat();
+ float resolution = in.readFloat();
+ float power = in.readFloat();
+ int minDelay = in.readInt();
+ int fifoReservedEventCount = in.readInt();
+ int fifoMaxEventCount = in.readInt();
+ String stringType = in.readString();
+ String requiredPermission = in.readString();
+ int maxDelay = in.readInt();
+ int flags = in.readInt();
+ int id = in.readInt();
+
+ this.mName = name;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mName);
+ this.mVendor = vendor;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mVendor);
+ this.mVersion = version;
+ this.mHandle = handle;
+ this.mType = type;
+ this.mMaxRange = maxRange;
+ this.mResolution = resolution;
+ this.mPower = power;
+ this.mMinDelay = minDelay;
+ this.mFifoReservedEventCount = fifoReservedEventCount;
+ this.mFifoMaxEventCount = fifoMaxEventCount;
+ this.mStringType = stringType;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mStringType);
+ this.mRequiredPermission = requiredPermission;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mRequiredPermission);
+ this.mMaxDelay = maxDelay;
+ this.mFlags = flags;
+ this.mId = id;
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<InputSensorInfo> CREATOR
+ = new Parcelable.Creator<InputSensorInfo>() {
+ @Override
+ public InputSensorInfo[] newArray(int size) {
+ return new InputSensorInfo[size];
+ }
+
+ @Override
+ public InputSensorInfo createFromParcel(@NonNull Parcel in) {
+ return new InputSensorInfo(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1605294854951L,
+ codegenVersion = "1.0.20",
+ sourceFile = "frameworks/base/core/java/android/hardware/input/InputSensorInfo.java",
+ inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mVendor\nprivate int mVersion\nprivate int mHandle\nprivate int mType\nprivate float mMaxRange\nprivate float mResolution\nprivate float mPower\nprivate int mMinDelay\nprivate int mFifoReservedEventCount\nprivate int mFifoMaxEventCount\nprivate @android.annotation.NonNull java.lang.String mStringType\nprivate @android.annotation.NonNull java.lang.String mRequiredPermission\nprivate int mMaxDelay\nprivate int mFlags\nprivate int mId\nclass InputSensorInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 6831eca..df9a7c2 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1700,8 +1700,12 @@
if (config.orientation != Configuration.ORIENTATION_LANDSCAPE) {
return false;
}
- if (mInputEditorInfo != null
- && (mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0) {
+ if ((mInputEditorInfo != null
+ && (mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0)
+ // If app window has portrait orientation, regardless of what display orientation
+ // is, IME shouldn't use fullscreen-mode.
+ || (mInputEditorInfo.internalImeOptions
+ & EditorInfo.IME_FLAG_APP_WINDOW_PORTRAIT) != 0) {
return false;
}
return true;
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index fb01283..95a2f2e 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -31,6 +31,7 @@
import android.net.ProxyInfo;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.INetworkActivityListener;
import android.os.Messenger;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
@@ -233,4 +234,10 @@
in PersistableBundle extras);
void systemReady();
+
+ void registerNetworkActivityListener(in INetworkActivityListener l);
+
+ void unregisterNetworkActivityListener(in INetworkActivityListener l);
+
+ boolean isDefaultNetworkActive();
}
diff --git a/core/java/android/net/INetworkManagementEventObserver.aidl b/core/java/android/net/INetworkManagementEventObserver.aidl
index f0fe92e..55ae218 100644
--- a/core/java/android/net/INetworkManagementEventObserver.aidl
+++ b/core/java/android/net/INetworkManagementEventObserver.aidl
@@ -85,11 +85,14 @@
/**
* Interface data activity status is changed.
*
- * @param iface The interface.
+ * @param label Unique identifier indicates the network type of the data activity change.
* @param active True if the interface is actively transmitting data, false if it is idle.
* @param tsNanos Elapsed realtime in nanos when the state of the network interface changed.
+ * @param uid Uid of this event. It represents the uid that was responsible for waking the
+ * radio. For those events that are reported by system itself, not from specific uid,
+ * use -1 for the events which means no uid.
*/
- void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos);
+ void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos, int uid);
/**
* Information about available DNS servers has been received.
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index fba7561..bf25602 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -26,9 +26,9 @@
import static android.net.NetworkStatsHistory.Entry.UNKNOWN;
import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray;
import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray;
-import static android.net.NetworkUtils.multiplySafeByRational;
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
+import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational;
import static com.android.internal.util.ArrayUtils.total;
import android.compat.annotation.UnsupportedAppUsage;
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index d84ee2a..b5962c5 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -16,14 +16,9 @@
package android.net;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-
-import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.system.ErrnoException;
-import android.system.Os;
import android.util.Log;
import android.util.Pair;
@@ -155,14 +150,6 @@
public static native Network getDnsNetwork() throws ErrnoException;
/**
- * Allow/Disallow creating AF_INET/AF_INET6 sockets and DNS lookups for current process.
- *
- * @param allowNetworking whether to allow or disallow creating AF_INET/AF_INET6 sockets
- * and DNS lookups.
- */
- public static native void setAllowNetworkingForProcess(boolean allowNetworking);
-
- /**
* Get the tcp repair window associated with the {@code fd}.
*
* @param fd the tcp socket's {@link FileDescriptor}.
@@ -437,60 +424,4 @@
return routedIPCount;
}
- private static final int[] ADDRESS_FAMILIES = new int[] {AF_INET, AF_INET6};
-
- /**
- * Returns true if the hostname is weakly validated.
- * @param hostname Name of host to validate.
- * @return True if it's a valid-ish hostname.
- *
- * @hide
- */
- public static boolean isWeaklyValidatedHostname(@NonNull String hostname) {
- // TODO(b/34953048): Use a validation method that permits more accurate,
- // but still inexpensive, checking of likely valid DNS hostnames.
- final String weakHostnameRegex = "^[a-zA-Z0-9_.-]+$";
- if (!hostname.matches(weakHostnameRegex)) {
- return false;
- }
-
- for (int address_family : ADDRESS_FAMILIES) {
- if (Os.inet_pton(address_family, hostname) != null) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Safely multiple a value by a rational.
- * <p>
- * Internally it uses integer-based math whenever possible, but switches
- * over to double-based math if values would overflow.
- * @hide
- */
- public static long multiplySafeByRational(long value, long num, long den) {
- if (den == 0) {
- throw new ArithmeticException("Invalid Denominator");
- }
- long x = value;
- long y = num;
-
- // Logic shamelessly borrowed from Math.multiplyExact()
- long r = x * y;
- long ax = Math.abs(x);
- long ay = Math.abs(y);
- if (((ax | ay) >>> 31 != 0)) {
- // Some bits greater than 2^31 that might cause overflow
- // Check the result using the divide operator
- // and check for the special case of Long.MIN_VALUE * -1
- if (((y != 0) && (r / y != x)) ||
- (x == Long.MIN_VALUE && y == -1)) {
- // Use double math to avoid overflowing
- return (long) (((double) num / den) * value);
- }
- }
- return r / den;
- }
}
diff --git a/core/java/android/net/vcn/VcnConfig.java b/core/java/android/net/vcn/VcnConfig.java
index 148acf1..d4a3fa7 100644
--- a/core/java/android/net/vcn/VcnConfig.java
+++ b/core/java/android/net/vcn/VcnConfig.java
@@ -15,30 +15,104 @@
*/
package android.net.vcn;
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.PersistableBundle;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Set;
/**
* This class represents a configuration for a Virtual Carrier Network.
*
+ * <p>Each {@link VcnGatewayConnectionConfig} instance added represents a connection that will be
+ * brought up on demand based on active {@link NetworkRequest}(s).
+ *
+ * @see VcnManager for more information on the Virtual Carrier Network feature
* @hide
*/
public final class VcnConfig implements Parcelable {
@NonNull private static final String TAG = VcnConfig.class.getSimpleName();
- private VcnConfig() {
+ private static final String GATEWAY_CONNECTION_CONFIGS_KEY = "mGatewayConnectionConfigs";
+ @NonNull private final Set<VcnGatewayConnectionConfig> mGatewayConnectionConfigs;
+
+ private VcnConfig(@NonNull Set<VcnGatewayConnectionConfig> tunnelConfigs) {
+ mGatewayConnectionConfigs = Collections.unmodifiableSet(tunnelConfigs);
+
validate();
}
- // TODO: Implement getters, validators, etc
/**
- * Validates this configuration.
+ * Deserializes a VcnConfig from a PersistableBundle.
*
* @hide
*/
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public VcnConfig(@NonNull PersistableBundle in) {
+ final PersistableBundle gatewayConnectionConfigsBundle =
+ in.getPersistableBundle(GATEWAY_CONNECTION_CONFIGS_KEY);
+ mGatewayConnectionConfigs =
+ new ArraySet<>(
+ PersistableBundleUtils.toList(
+ gatewayConnectionConfigsBundle, VcnGatewayConnectionConfig::new));
+
+ validate();
+ }
+
private void validate() {
- // TODO: implement validation logic
+ Preconditions.checkCollectionNotEmpty(
+ mGatewayConnectionConfigs, "gatewayConnectionConfigs");
+ }
+
+ /** Retrieves the set of configured tunnels. */
+ @NonNull
+ public Set<VcnGatewayConnectionConfig> getGatewayConnectionConfigs() {
+ return Collections.unmodifiableSet(mGatewayConnectionConfigs);
+ }
+
+ /**
+ * Serializes this object to a PersistableBundle.
+ *
+ * @hide
+ */
+ @NonNull
+ public PersistableBundle toPersistableBundle() {
+ final PersistableBundle result = new PersistableBundle();
+
+ final PersistableBundle gatewayConnectionConfigsBundle =
+ PersistableBundleUtils.fromList(
+ new ArrayList<>(mGatewayConnectionConfigs),
+ VcnGatewayConnectionConfig::toPersistableBundle);
+ result.putPersistableBundle(GATEWAY_CONNECTION_CONFIGS_KEY, gatewayConnectionConfigsBundle);
+
+ return result;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mGatewayConnectionConfigs);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object other) {
+ if (!(other instanceof VcnConfig)) {
+ return false;
+ }
+
+ final VcnConfig rhs = (VcnConfig) other;
+ return mGatewayConnectionConfigs.equals(rhs.mGatewayConnectionConfigs);
}
// Parcelable methods
@@ -49,15 +123,16 @@
}
@Override
- public void writeToParcel(Parcel out, int flags) {}
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeParcelable(toPersistableBundle(), flags);
+ }
@NonNull
public static final Parcelable.Creator<VcnConfig> CREATOR =
new Parcelable.Creator<VcnConfig>() {
@NonNull
public VcnConfig createFromParcel(Parcel in) {
- // TODO: Ensure all methods are pulled from the parcels
- return new VcnConfig();
+ return new VcnConfig((PersistableBundle) in.readParcelable(null));
}
@NonNull
@@ -68,7 +143,23 @@
/** This class is used to incrementally build {@link VcnConfig} objects. */
public static class Builder {
- // TODO: Implement this builder
+ @NonNull
+ private final Set<VcnGatewayConnectionConfig> mGatewayConnectionConfigs = new ArraySet<>();
+
+ /**
+ * Adds a configuration for an individual gateway connection.
+ *
+ * @param gatewayConnectionConfig the configuration for an individual gateway connection
+ * @return this {@link Builder} instance, for chaining
+ */
+ @NonNull
+ public Builder addGatewayConnectionConfig(
+ @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig) {
+ Objects.requireNonNull(gatewayConnectionConfig, "gatewayConnectionConfig was null");
+
+ mGatewayConnectionConfigs.add(gatewayConnectionConfig);
+ return this;
+ }
/**
* Builds and validates the VcnConfig.
@@ -77,7 +168,7 @@
*/
@NonNull
public VcnConfig build() {
- return new VcnConfig();
+ return new VcnConfig(mGatewayConnectionConfigs);
}
}
}
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index 8160edc..039360a 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -15,7 +15,27 @@
*/
package android.net.vcn;
+import static android.net.NetworkCapabilities.NetCapability;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import android.annotation.IntRange;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.NetworkCapabilities;
+import android.os.PersistableBundle;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
/**
* This class represents a configuration for a connection to a Virtual Carrier Network gateway.
@@ -49,38 +69,399 @@
* <li>{@link android.net.NetworkCapabilities.NET_CAPABILITY_MCX}
* </ul>
*
+ * <p>The meteredness and roaming of the VCN {@link Network} will be determined by that of the
+ * underlying Network(s).
+ *
* @hide
*/
public final class VcnGatewayConnectionConfig {
- private VcnGatewayConnectionConfig() {
+ // TODO: Use MIN_MTU_V6 once it is public, @hide
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ static final int MIN_MTU_V6 = 1280;
+
+ private static final Set<Integer> ALLOWED_CAPABILITIES;
+
+ static {
+ Set<Integer> allowedCaps = new ArraySet<>();
+ allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_MMS);
+ allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_SUPL);
+ allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_DUN);
+ allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_FOTA);
+ allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_IMS);
+ allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_CBS);
+ allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_IA);
+ allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_RCS);
+ allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_XCAP);
+ allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_EIMS);
+ allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_MCX);
+
+ ALLOWED_CAPABILITIES = Collections.unmodifiableSet(allowedCaps);
+ }
+
+ private static final int DEFAULT_MAX_MTU = 1500;
+
+ /**
+ * The maximum number of retry intervals that may be specified.
+ *
+ * <p>Limited to ensure an upper bound on config sizes.
+ */
+ private static final int MAX_RETRY_INTERVAL_COUNT = 10;
+
+ /**
+ * The minimum allowable repeating retry interval
+ *
+ * <p>To ensure the device is not constantly being woken up, this retry interval MUST be greater
+ * than this value.
+ *
+ * @see {@link Builder#setRetryInterval()}
+ */
+ private static final long MINIMUM_REPEATING_RETRY_INTERVAL_MS = TimeUnit.MINUTES.toMillis(15);
+
+ private static final long[] DEFAULT_RETRY_INTERVALS_MS =
+ new long[] {
+ TimeUnit.SECONDS.toMillis(1),
+ TimeUnit.SECONDS.toMillis(2),
+ TimeUnit.SECONDS.toMillis(5),
+ TimeUnit.SECONDS.toMillis(30),
+ TimeUnit.MINUTES.toMillis(1),
+ TimeUnit.MINUTES.toMillis(5),
+ TimeUnit.MINUTES.toMillis(15)
+ };
+
+ private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities";
+ @NonNull private final Set<Integer> mExposedCapabilities;
+
+ private static final String UNDERLYING_CAPABILITIES_KEY = "mUnderlyingCapabilities";
+ @NonNull private final Set<Integer> mUnderlyingCapabilities;
+
+ // TODO: Add Ike/ChildSessionParams as a subclass - maybe VcnIkeGatewayConnectionConfig
+
+ private static final String MAX_MTU_KEY = "mMaxMtu";
+ private final int mMaxMtu;
+
+ private static final String RETRY_INTERVAL_MS_KEY = "mRetryIntervalsMs";
+ @NonNull private final long[] mRetryIntervalsMs;
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public VcnGatewayConnectionConfig(
+ @NonNull Set<Integer> exposedCapabilities,
+ @NonNull Set<Integer> underlyingCapabilities,
+ @NonNull long[] retryIntervalsMs,
+ @IntRange(from = MIN_MTU_V6) int maxMtu) {
+ mExposedCapabilities = exposedCapabilities;
+ mUnderlyingCapabilities = underlyingCapabilities;
+ mRetryIntervalsMs = retryIntervalsMs;
+ mMaxMtu = maxMtu;
+
validate();
}
- // TODO: Implement getters, validators, etc
+ /** @hide */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public VcnGatewayConnectionConfig(@NonNull PersistableBundle in) {
+ final PersistableBundle exposedCapsBundle =
+ in.getPersistableBundle(EXPOSED_CAPABILITIES_KEY);
+ final PersistableBundle underlyingCapsBundle =
+ in.getPersistableBundle(UNDERLYING_CAPABILITIES_KEY);
+
+ mExposedCapabilities = new ArraySet<>(PersistableBundleUtils.toList(
+ exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER));
+ mUnderlyingCapabilities = new ArraySet<>(PersistableBundleUtils.toList(
+ underlyingCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER));
+ mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY);
+ mMaxMtu = in.getInt(MAX_MTU_KEY);
+
+ validate();
+ }
+
+ private void validate() {
+ Preconditions.checkArgument(
+ mExposedCapabilities != null && !mExposedCapabilities.isEmpty(),
+ "exposedCapsBundle was null or empty");
+ for (Integer cap : getAllExposedCapabilities()) {
+ checkValidCapability(cap);
+ }
+
+ Preconditions.checkArgument(
+ mUnderlyingCapabilities != null && !mUnderlyingCapabilities.isEmpty(),
+ "underlyingCapabilities was null or empty");
+ for (Integer cap : getAllUnderlyingCapabilities()) {
+ checkValidCapability(cap);
+ }
+
+ Objects.requireNonNull(mRetryIntervalsMs, "retryIntervalsMs was null");
+ validateRetryInterval(mRetryIntervalsMs);
+
+ Preconditions.checkArgument(
+ mMaxMtu >= MIN_MTU_V6, "maxMtu must be at least IPv6 min MTU (1280)");
+ }
+
+ private static void checkValidCapability(int capability) {
+ Preconditions.checkArgument(
+ ALLOWED_CAPABILITIES.contains(capability),
+ "NetworkCapability " + capability + "out of range");
+ }
+
+ private static void validateRetryInterval(@Nullable long[] retryIntervalsMs) {
+ Preconditions.checkArgument(
+ retryIntervalsMs != null
+ && retryIntervalsMs.length > 0
+ && retryIntervalsMs.length <= MAX_RETRY_INTERVAL_COUNT,
+ "retryIntervalsMs was null, empty or exceed max interval count");
+
+ final long repeatingInterval = retryIntervalsMs[retryIntervalsMs.length - 1];
+ if (repeatingInterval < MINIMUM_REPEATING_RETRY_INTERVAL_MS) {
+ throw new IllegalArgumentException(
+ "Repeating retry interval was too short, must be a minimum of 15 minutes: "
+ + repeatingInterval);
+ }
+ }
/**
- * Validates this configuration
+ * Returns all exposed capabilities.
*
* @hide
*/
- private void validate() {
- // TODO: implement validation logic
+ @NonNull
+ public Set<Integer> getAllExposedCapabilities() {
+ return Collections.unmodifiableSet(mExposedCapabilities);
}
- // Parcelable methods
+ /**
+ * Checks if this config is configured to support/expose a specific capability.
+ *
+ * @param capability the capability to check for
+ */
+ public boolean hasExposedCapability(@NetCapability int capability) {
+ checkValidCapability(capability);
- /** This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects */
+ return mExposedCapabilities.contains(capability);
+ }
+
+ /**
+ * Returns all capabilities required of underlying networks.
+ *
+ * @hide
+ */
+ @NonNull
+ public Set<Integer> getAllUnderlyingCapabilities() {
+ return Collections.unmodifiableSet(mUnderlyingCapabilities);
+ }
+
+ /**
+ * Checks if this config requires an underlying network to have the specified capability.
+ *
+ * @param capability the capability to check for
+ */
+ public boolean requiresUnderlyingCapability(@NetCapability int capability) {
+ checkValidCapability(capability);
+
+ return mUnderlyingCapabilities.contains(capability);
+ }
+
+ /** Retrieves the configured retry intervals. */
+ @NonNull
+ public long[] getRetryIntervalsMs() {
+ return Arrays.copyOf(mRetryIntervalsMs, mRetryIntervalsMs.length);
+ }
+
+ /** Retrieves the maximum MTU allowed for this Gateway Connection. */
+ @IntRange(from = MIN_MTU_V6)
+ public int getMaxMtu() {
+ return mMaxMtu;
+ }
+
+ /**
+ * Converts this config to a PersistableBundle.
+ *
+ * @hide
+ */
+ @NonNull
+ @VisibleForTesting(visibility = Visibility.PROTECTED)
+ public PersistableBundle toPersistableBundle() {
+ final PersistableBundle result = new PersistableBundle();
+
+ final PersistableBundle exposedCapsBundle =
+ PersistableBundleUtils.fromList(
+ new ArrayList<>(mExposedCapabilities),
+ PersistableBundleUtils.INTEGER_SERIALIZER);
+ final PersistableBundle underlyingCapsBundle =
+ PersistableBundleUtils.fromList(
+ new ArrayList<>(mUnderlyingCapabilities),
+ PersistableBundleUtils.INTEGER_SERIALIZER);
+
+ result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle);
+ result.putPersistableBundle(UNDERLYING_CAPABILITIES_KEY, underlyingCapsBundle);
+ result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs);
+ result.putInt(MAX_MTU_KEY, mMaxMtu);
+
+ return result;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mExposedCapabilities,
+ mUnderlyingCapabilities,
+ Arrays.hashCode(mRetryIntervalsMs),
+ mMaxMtu);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object other) {
+ if (!(other instanceof VcnGatewayConnectionConfig)) {
+ return false;
+ }
+
+ final VcnGatewayConnectionConfig rhs = (VcnGatewayConnectionConfig) other;
+ return mExposedCapabilities.equals(rhs.mExposedCapabilities)
+ && mUnderlyingCapabilities.equals(rhs.mUnderlyingCapabilities)
+ && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs)
+ && mMaxMtu == rhs.mMaxMtu;
+ }
+
+ /** This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects. */
public static class Builder {
- // TODO: Implement this builder
+ @NonNull private final Set<Integer> mExposedCapabilities = new ArraySet();
+ @NonNull private final Set<Integer> mUnderlyingCapabilities = new ArraySet();
+ @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS;
+ private int mMaxMtu = DEFAULT_MAX_MTU;
+
+ // TODO: (b/175829816) Consider VCN-exposed capabilities that may be transport dependent.
+ // Consider the case where the VCN might only expose MMS on WiFi, but defer to MMS
+ // when on Cell.
/**
- * Builds and validates the VcnGatewayConnectionConfig
+ * Add a capability that this VCN Gateway Connection will support.
+ *
+ * @param exposedCapability the app-facing capability to be exposed by this VCN Gateway
+ * Connection (i.e., the capabilities that this VCN Gateway Connection will support).
+ * @return this {@link Builder} instance, for chaining
+ * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway
+ * Connection
+ */
+ public Builder addExposedCapability(@NetCapability int exposedCapability) {
+ checkValidCapability(exposedCapability);
+
+ mExposedCapabilities.add(exposedCapability);
+ return this;
+ }
+
+ /**
+ * Remove a capability that this VCN Gateway Connection will support.
+ *
+ * @param exposedCapability the app-facing capability to not be exposed by this VCN Gateway
+ * Connection (i.e., the capabilities that this VCN Gateway Connection will support)
+ * @return this {@link Builder} instance, for chaining
+ * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway
+ * Connection
+ */
+ public Builder removeExposedCapability(@NetCapability int exposedCapability) {
+ checkValidCapability(exposedCapability);
+
+ mExposedCapabilities.remove(exposedCapability);
+ return this;
+ }
+
+ /**
+ * Require a capability for Networks underlying this VCN Gateway Connection.
+ *
+ * @param underlyingCapability the capability that a network MUST have in order to be an
+ * underlying network for this VCN Gateway Connection.
+ * @return this {@link Builder} instance, for chaining
+ * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying
+ * networks
+ */
+ public Builder addRequiredUnderlyingCapability(@NetCapability int underlyingCapability) {
+ checkValidCapability(underlyingCapability);
+
+ mUnderlyingCapabilities.add(underlyingCapability);
+ return this;
+ }
+
+ /**
+ * Remove a requirement of a capability for Networks underlying this VCN Gateway Connection.
+ *
+ * <p>Calling this method will allow Networks that do NOT have this capability to be
+ * selected as an underlying network for this VCN Gateway Connection. However, underlying
+ * networks MAY still have the removed capability.
+ *
+ * @param underlyingCapability the capability that a network DOES NOT need to have in order
+ * to be an underlying network for this VCN Gateway Connection.
+ * @return this {@link Builder} instance, for chaining
+ * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying
+ * networks
+ */
+ public Builder removeRequiredUnderlyingCapability(@NetCapability int underlyingCapability) {
+ checkValidCapability(underlyingCapability);
+
+ mUnderlyingCapabilities.remove(underlyingCapability);
+ return this;
+ }
+
+ /**
+ * Set the retry interval between VCN establishment attempts upon successive failures.
+ *
+ * <p>The last retry interval will be repeated until safe mode is entered, or a connection
+ * is successfully established, at which point the retry timers will be reset. For power
+ * reasons, the last (repeated) retry interval MUST be at least 15 minutes.
+ *
+ * <p>Retry intervals MAY be subject to system power saving modes. That is to say that if
+ * the system enters a power saving mode, the retry may not occur until the device leaves
+ * the specified power saving mode. Intervals are sequential, and intervals will NOT be
+ * skipped if system power saving results in delaying retries (even if it exceed multiple
+ * retry intervals).
+ *
+ * <p>Each Gateway Connection will retry according to the retry intervals configured, but if
+ * safe mode is enabled, all Gateway Connection(s) will be disabled.
+ *
+ * @param retryIntervalsMs an array of between 1 and 10 millisecond intervals after which
+ * the VCN will attempt to retry a session initiation. The last (repeating) retry
+ * interval must be at least 15 minutes. Defaults to: {@code [1s, 2s, 5s, 30s, 1m, 5m,
+ * 15m]}
+ * @return this {@link Builder} instance, for chaining
+ * @see VcnManager for additional discussion on fail-safe mode
+ */
+ @NonNull
+ public Builder setRetryInterval(@NonNull long[] retryIntervalsMs) {
+ validateRetryInterval(retryIntervalsMs);
+
+ mRetryIntervalsMs = retryIntervalsMs;
+ return this;
+ }
+
+ /**
+ * Sets the maximum MTU allowed for this VCN Gateway Connection.
+ *
+ * <p>This MTU is applied to the VCN Gateway Connection exposed Networks, and represents the
+ * MTU of the virtualized network.
+ *
+ * <p>The system may reduce the MTU below the maximum specified based on signals such as the
+ * MTU of the underlying networks (and adjusted for Gateway Connection overhead).
+ *
+ * @param maxMtu the maximum MTU allowed for this Gateway Connection. Must be greater than
+ * the IPv6 minimum MTU of 1280. Defaults to 1500.
+ * @return this {@link Builder} instance, for chaining
+ */
+ @NonNull
+ public Builder setMaxMtu(@IntRange(from = MIN_MTU_V6) int maxMtu) {
+ Preconditions.checkArgument(
+ maxMtu >= MIN_MTU_V6, "maxMtu must be at least IPv6 min MTU (1280)");
+
+ mMaxMtu = maxMtu;
+ return this;
+ }
+
+ /**
+ * Builds and validates the VcnGatewayConnectionConfig.
*
* @return an immutable VcnGatewayConnectionConfig instance
*/
@NonNull
public VcnGatewayConnectionConfig build() {
- return new VcnGatewayConnectionConfig();
+ return new VcnGatewayConnectionConfig(
+ mExposedCapabilities, mUnderlyingCapabilities, mRetryIntervalsMs, mMaxMtu);
}
}
}
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index 6769b9e..19c183f 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -23,10 +23,37 @@
import android.content.Context;
import android.os.ParcelUuid;
import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+
+import java.io.IOException;
/**
* VcnManager publishes APIs for applications to configure and manage Virtual Carrier Networks.
*
+ * <p>A VCN creates a virtualization layer to allow MVNOs to aggregate heterogeneous physical
+ * networks, unifying them as a single carrier network. This enables infrastructure flexibility on
+ * the part of MVNOs without impacting user connectivity, abstracting the physical network
+ * technologies as an implementation detail of their public network.
+ *
+ * <p>Each VCN virtualizes an Carrier's network by building tunnels to a carrier's core network over
+ * carrier-managed physical links and supports a IP mobility layer to ensure seamless transitions
+ * between the underlying networks. Each VCN is configured based on a Subscription Group (see {@link
+ * android.telephony.SubscriptionManager}) and aggregates all networks that are brought up based on
+ * a profile or suggestion in the specified Subscription Group.
+ *
+ * <p>The VCN can be configured to expose one or more {@link android.net.Network}(s), each with
+ * different capabilities, allowing for APN virtualization.
+ *
+ * <p>If a tunnel fails to connect, or otherwise encounters a fatal error, the VCN will attempt to
+ * reestablish the connection. If the tunnel still has not reconnected after a system-determined
+ * timeout, the VCN Safe Mode (see below) will be entered.
+ *
+ * <p>The VCN Safe Mode ensures that users (and carriers) have a fallback to restore system
+ * connectivity to update profiles, diagnose issues, contact support, or perform other remediation
+ * tasks. In Safe Mode, the system will allow underlying cellular networks to be used as default.
+ * Additionally, during Safe Mode, the VCN will continue to retry the connections, and will
+ * automatically exit Safe Mode if all active tunnels connect successfully.
+ *
* @hide
*/
@SystemService(Context.VCN_MANAGEMENT_SERVICE)
@@ -63,15 +90,20 @@
* @param config the configuration parameters for the VCN
* @throws SecurityException if the caller does not have carrier privileges, or is not running
* as the primary user
+ * @throws IOException if the configuration failed to be persisted. A caller encountering this
+ * exception should attempt to retry (possibly after a delay).
* @hide
*/
@RequiresPermission("carrier privileges") // TODO (b/72967236): Define a system-wide constant
- public void setVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) {
+ public void setVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config)
+ throws IOException {
requireNonNull(subscriptionGroup, "subscriptionGroup was null");
requireNonNull(config, "config was null");
try {
mService.setVcnConfig(subscriptionGroup, config);
+ } catch (ServiceSpecificException e) {
+ throw new IOException(e);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -88,14 +120,18 @@
* @param subscriptionGroup the subscription group that the configuration should be applied to
* @throws SecurityException if the caller does not have carrier privileges, or is not running
* as the primary user
+ * @throws IOException if the configuration failed to be cleared. A caller encountering this
+ * exception should attempt to retry (possibly after a delay).
* @hide
*/
@RequiresPermission("carrier privileges") // TODO (b/72967236): Define a system-wide constant
- public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup) {
+ public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup) throws IOException {
requireNonNull(subscriptionGroup, "subscriptionGroup was null");
try {
mService.clearVcnConfig(subscriptionGroup);
+ } catch (ServiceSpecificException e) {
+ throw new IOException(e);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
index c476a59..bf8ac6e 100644
--- a/core/java/android/os/BatteryConsumer.java
+++ b/core/java/android/os/BatteryConsumer.java
@@ -36,7 +36,9 @@
* @hide
*/
@IntDef(prefix = {"POWER_COMPONENT_"}, value = {
+ POWER_COMPONENT_USAGE,
POWER_COMPONENT_CPU,
+ POWER_COMPONENT_BLUETOOTH,
})
@Retention(RetentionPolicy.SOURCE)
public static @interface PowerComponent {
@@ -44,8 +46,9 @@
public static final int POWER_COMPONENT_USAGE = 0;
public static final int POWER_COMPONENT_CPU = 1;
+ public static final int POWER_COMPONENT_BLUETOOTH = 2;
- public static final int POWER_COMPONENT_COUNT = 2;
+ public static final int POWER_COMPONENT_COUNT = 3;
public static final int FIRST_CUSTOM_POWER_COMPONENT_ID = 1000;
public static final int LAST_CUSTOM_POWER_COMPONENT_ID = 9999;
@@ -68,8 +71,10 @@
* @hide
*/
@IntDef(prefix = {"TIME_COMPONENT_"}, value = {
+ TIME_COMPONENT_USAGE,
TIME_COMPONENT_CPU,
TIME_COMPONENT_CPU_FOREGROUND,
+ TIME_COMPONENT_BLUETOOTH,
})
@Retention(RetentionPolicy.SOURCE)
public static @interface TimeComponent {
@@ -78,8 +83,9 @@
public static final int TIME_COMPONENT_USAGE = 0;
public static final int TIME_COMPONENT_CPU = 1;
public static final int TIME_COMPONENT_CPU_FOREGROUND = 2;
+ public static final int TIME_COMPONENT_BLUETOOTH = 3;
- public static final int TIME_COMPONENT_COUNT = 3;
+ public static final int TIME_COMPONENT_COUNT = 4;
public static final int FIRST_CUSTOM_TIME_COMPONENT_ID = 1000;
public static final int LAST_CUSTOM_TIME_COMPONENT_ID = 9999;
diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java
index 3191eda..f21a812 100644
--- a/core/java/android/os/BatteryStatsManager.java
+++ b/core/java/android/os/BatteryStatsManager.java
@@ -26,6 +26,7 @@
import android.content.Context;
import android.os.connectivity.CellularBatteryStats;
import android.os.connectivity.WifiBatteryStats;
+import android.telephony.DataConnectionRealTimeInfo;
import com.android.internal.app.IBatteryStats;
@@ -85,7 +86,7 @@
public static final int NUM_WIFI_STATES = WIFI_STATE_SOFT_AP + 1;
/** @hide */
- @IntDef(flag = true, prefix = { "WIFI_STATE_" }, value = {
+ @IntDef(prefix = { "WIFI_STATE_" }, value = {
WIFI_STATE_OFF,
WIFI_STATE_OFF_SCANNING,
WIFI_STATE_ON_NO_NETWORKS,
@@ -135,7 +136,7 @@
public static final int NUM_WIFI_SUPPL_STATES = WIFI_SUPPL_STATE_UNINITIALIZED + 1;
/** @hide */
- @IntDef(flag = true, prefix = { "WIFI_SUPPL_STATE_" }, value = {
+ @IntDef(prefix = { "WIFI_SUPPL_STATE_" }, value = {
WIFI_SUPPL_STATE_INVALID,
WIFI_SUPPL_STATE_DISCONNECTED,
WIFI_SUPPL_STATE_INTERFACE_DISABLED,
@@ -405,4 +406,50 @@
e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Indicates that the radio power state has changed.
+ *
+ * @param isActive indicates if the mobile radio is powered.
+ * @param uid Uid of this event. For the active state it represents the uid that was responsible
+ * for waking the radio, or -1 if the system was responsible for waking the radio.
+ * For inactive state, the UID should always be -1.
+ * @throws RuntimeException if there are binder remote-invocation errors.
+ */
+ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+ public void reportMobileRadioPowerState(boolean isActive, int uid) throws RuntimeException {
+ try {
+ mBatteryStats.noteMobileRadioPowerState(getDataConnectionPowerState(isActive),
+ SystemClock.elapsedRealtimeNanos(), uid);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Indicates that the wifi power state has changed.
+ *
+ * @param isActive indicates if the wifi radio is powered.
+ * @param uid Uid of this event. For the active state it represents the uid that was responsible
+ * for waking the radio, or -1 if the system was responsible for waking the radio.
+ * For inactive state, the UID should always be -1.
+ * @throws RuntimeException if there are binder remote-invocation errors.
+ */
+ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+ public void reportWifiRadioPowerState(boolean isActive, int uid) throws RuntimeException {
+ try {
+ mBatteryStats.noteWifiRadioPowerState(getDataConnectionPowerState(isActive),
+ SystemClock.elapsedRealtimeNanos(), uid);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ private static int getDataConnectionPowerState(boolean isActive) {
+ // TODO: DataConnectionRealTimeInfo is under telephony package but the constants are used
+ // for both Wifi and mobile. It would make more sense to separate the constants to a generic
+ // class or move it to generic package.
+ return isActive ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
+ : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
+ }
}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index e2e1bbe..9584bc7 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -2582,6 +2582,13 @@
public static native long getIonMappedSizeKb();
/**
+ * Return memory size in kilobytes used by GPU.
+ *
+ * @hide
+ */
+ public static native long getGpuTotalUsageKb();
+
+ /**
* Return whether virtually-mapped kernel stacks are enabled (CONFIG_VMAP_STACK).
* Note: caller needs config_gz read sepolicy permission
*
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 92fe98c..c014ef6 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -83,6 +83,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
+import java.util.Locale;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
@@ -115,6 +116,9 @@
private FileUtils() {
}
+ private static final String CAMERA_DIR_LOWER_CASE = "/storage/emulated/" + UserHandle.myUserId()
+ + "/dcim/camera";
+
/** Regular expression for safe filenames: no spaces or metacharacters.
*
* Use a preload holder so that FileUtils can be compile-time initialized.
@@ -1432,18 +1436,27 @@
}
}
+ // TODO(b/170488060): Consider better approach
/** {@hide} */
+ @VisibleForTesting
public static FileDescriptor convertToModernFd(FileDescriptor fd) {
try {
Context context = AppGlobals.getInitialApplication();
+ File realFile = ParcelFileDescriptor.getFile(fd);
+ String fileName = realFile.getName();
+ boolean isCameraVideo = !fileName.startsWith(".") && fileName.endsWith(".mp4")
+ && contains(CAMERA_DIR_LOWER_CASE, realFile.getAbsolutePath().toLowerCase(
+ Locale.ROOT));
+
if (!SystemProperties.getBoolean("sys.fuse.transcode_enabled", false)
- || UserHandle.getAppId(Process.myUid()) == getMediaProviderAppId(context)) {
- // If transcode is enabled we optimize by default, unless explicitly disabled.
- // Never convert modern fd for MediaProvider, because this requires
+ || UserHandle.getAppId(Process.myUid()) == getMediaProviderAppId(context)
+ || !isCameraVideo) {
+ // 1. If transcode is enabled we optimize by default, unless explicitly disabled.
+ // 2. Never convert modern fd for MediaProvider, because this requires
// MediaStore#scanFile and can cause infinite loops when MediaProvider scans
+ // 3. Only convert published mp4 videos in the DCIM/Camera dir
return null;
}
- File realFile = ParcelFileDescriptor.getFile(fd);
Log.i(TAG, "Changing to modern format dataSource for: " + realFile);
ContentResolver resolver = context.getContentResolver();
diff --git a/core/java/android/os/IRecoverySystem.aidl b/core/java/android/os/IRecoverySystem.aidl
index 5f8b932..2052883 100644
--- a/core/java/android/os/IRecoverySystem.aidl
+++ b/core/java/android/os/IRecoverySystem.aidl
@@ -30,5 +30,6 @@
boolean requestLskf(in String packageName, in IntentSender sender);
boolean clearLskf(in String packageName);
boolean isLskfCaptured(in String packageName);
+ boolean rebootWithLskfAssumeSlotSwitch(in String packageName, in String reason);
boolean rebootWithLskf(in String packageName, in String reason, in boolean slotSwitch);
}
diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java
index 4a73b24..18dca68 100644
--- a/core/java/android/os/PowerComponents.java
+++ b/core/java/android/os/PowerComponents.java
@@ -289,6 +289,15 @@
return this;
}
+ public void addPowerAndDuration(Builder other) {
+ for (int i = 0; i < mPowerComponents.length; i++) {
+ mPowerComponents[i] += other.mPowerComponents[i];
+ }
+ for (int i = 0; i < mTimeComponents.length; i++) {
+ mTimeComponents[i] += other.mTimeComponents[i];
+ }
+ }
+
/**
* Creates a read-only object out of the Builder values.
*/
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 5f3cfa3..93c1690 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -687,8 +687,8 @@
}
/**
- * Request that the device reboot and apply the update that has been prepared. Callers are
- * recommended to use {@link #rebootAndApply(Context, String, boolean)} instead.
+ * Request that the device reboot and apply the update that has been prepared. This API is
+ * deprecated, and is expected to be used by OTA only on devices running Android 11.
*
* @param context the Context to use.
* @param updateToken this parameter is deprecated and won't be used. See details in
@@ -699,18 +699,18 @@
* unattended reboot or if the {@code updateToken} did not match the previously
* given token
* @hide
+ * @deprecated Use {@link #rebootAndApply(Context, String, boolean)} instead
*/
@SystemApi
- @RequiresPermission(anyOf = {android.Manifest.permission.RECOVERY,
- android.Manifest.permission.REBOOT})
+ @RequiresPermission(android.Manifest.permission.RECOVERY)
public static void rebootAndApply(@NonNull Context context, @NonNull String updateToken,
@NonNull String reason) throws IOException {
if (updateToken == null) {
throw new NullPointerException("updateToken == null");
}
RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
- // OTA is the sole user before S, and a slot switch is required for ota update.
- if (!rs.rebootWithLskf(context.getPackageName(), reason, true)) {
+ // OTA is the sole user, who expects a slot switch.
+ if (!rs.rebootWithLskfAssumeSlotSwitch(context.getPackageName(), reason)) {
throw new IOException("system not prepared to apply update");
}
}
@@ -738,7 +738,7 @@
*
* @param context the Context to use.
* @param reason the reboot reason to give to the {@link PowerManager}
- * @param slotSwitch true if the caller intends to switch the slot on an A/B device.
+ * @param slotSwitch true if the caller expects the slot to be switched on A/B devices.
* @throws IOException if the reboot couldn't proceed because the device wasn't ready for an
* unattended reboot.
* @hide
@@ -1395,6 +1395,21 @@
}
}
+
+ /**
+ * Calls the recovery system service to reboot and apply update. This is the legacy API and
+ * expects a slot switch for A/B devices.
+ *
+ */
+ private boolean rebootWithLskfAssumeSlotSwitch(String packageName, String reason)
+ throws IOException {
+ try {
+ return mService.rebootWithLskfAssumeSlotSwitch(packageName, reason);
+ } catch (RemoteException e) {
+ throw new IOException("could not reboot for update");
+ }
+ }
+
/**
* Internally, recovery treats each line of the command file as a separate
* argv, so we only need to protect against newlines and nulls.
diff --git a/core/java/android/os/SystemBatteryConsumer.java b/core/java/android/os/SystemBatteryConsumer.java
index bda2f23..08e358f 100644
--- a/core/java/android/os/SystemBatteryConsumer.java
+++ b/core/java/android/os/SystemBatteryConsumer.java
@@ -21,6 +21,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
/**
@@ -118,6 +120,7 @@
public static final class Builder extends BaseBuilder<Builder> {
@DrainType
private final int mDrainType;
+ private List<UidBatteryConsumer.Builder> mUidBatteryConsumers;
Builder(int customPowerComponentCount, int customTimeComponentCount,
boolean includeModeledComponents, @DrainType int drainType) {
@@ -126,10 +129,35 @@
}
/**
+ * Add a UidBatteryConsumer to this SystemBatteryConsumer. For example,
+ * the UidBatteryConsumer with the UID == {@link Process#BLUETOOTH_UID} should
+ * be added to the SystemBatteryConsumer with the drain type == {@link
+ * #DRAIN_TYPE_BLUETOOTH}.
+ * <p>
+ * Calculated power and duration components of the added battery consumers
+ * are aggregated at the time the SystemBatteryConsumer is built by the {@link #build()}
+ * method.
+ * </p>
+ */
+ public void addUidBatteryConsumer(UidBatteryConsumer.Builder uidBatteryConsumerBuilder) {
+ if (mUidBatteryConsumers == null) {
+ mUidBatteryConsumers = new ArrayList<>();
+ }
+ mUidBatteryConsumers.add(uidBatteryConsumerBuilder);
+ }
+
+ /**
* Creates a read-only object out of the Builder values.
*/
@NonNull
public SystemBatteryConsumer build() {
+ if (mUidBatteryConsumers != null) {
+ for (int i = mUidBatteryConsumers.size() - 1; i >= 0; i--) {
+ UidBatteryConsumer.Builder uidBatteryConsumer = mUidBatteryConsumers.get(i);
+ mPowerComponentsBuilder.addPowerAndDuration(
+ uidBatteryConsumer.mPowerComponentsBuilder);
+ }
+ }
return new SystemBatteryConsumer(this);
}
}
diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java
index c5da22b..3161766 100644
--- a/core/java/android/os/UidBatteryConsumer.java
+++ b/core/java/android/os/UidBatteryConsumer.java
@@ -29,11 +29,21 @@
private final int mUid;
@Nullable
private final String mPackageWithHighestDrain;
+ private boolean mSystemComponent;
public int getUid() {
return mUid;
}
+ /**
+ * Returns true if this battery consumer is considered to be a part of the operating
+ * system itself. For example, the UidBatteryConsumer with the UID {@link Process#BLUETOOTH_UID}
+ * is a system component.
+ */
+ public boolean isSystemComponent() {
+ return mSystemComponent;
+ }
+
@Nullable
public String getPackageWithHighestDrain() {
return mPackageWithHighestDrain;
@@ -42,6 +52,7 @@
private UidBatteryConsumer(@NonNull Builder builder) {
super(builder.mPowerComponentsBuilder.build());
mUid = builder.mUid;
+ mSystemComponent = builder.mSystemComponent;
mPackageWithHighestDrain = builder.mPackageWithHighestDrain;
}
@@ -84,6 +95,7 @@
private final BatteryStats.Uid mBatteryStatsUid;
private final int mUid;
private String mPackageWithHighestDrain;
+ private boolean mSystemComponent;
public Builder(int customPowerComponentCount, int customTimeComponentCount,
boolean includeModeledComponents, BatteryStats.Uid batteryStatsUid) {
@@ -117,5 +129,14 @@
mPackageWithHighestDrain = packageName;
return this;
}
+
+ /**
+ * Marks the UidBatteryConsumer as part of the system. For example,
+ * the UidBatteryConsumer with the UID {@link Process#BLUETOOTH_UID} is considered
+ * as a system component.
+ */
+ public void setSystemComponent(boolean systemComponent) {
+ mSystemComponent = systemComponent;
+ }
}
}
diff --git a/core/java/android/os/incremental/OWNERS b/core/java/android/os/incremental/OWNERS
new file mode 100644
index 0000000..3795493
--- /dev/null
+++ b/core/java/android/os/incremental/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 554432
+alexbuy@google.com
+schfan@google.com
+toddke@google.com
+zyy@google.com
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 4ad17ef..441908d 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -56,13 +56,13 @@
void removeOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
- List<String> getWhitelistedRestrictedPermissions(String packageName,
+ List<String> getAllowlistedRestrictedPermissions(String packageName,
int flags, int userId);
- boolean addWhitelistedRestrictedPermission(String packageName, String permName,
+ boolean addAllowlistedRestrictedPermission(String packageName, String permissionName,
int flags, int userId);
- boolean removeWhitelistedRestrictedPermission(String packageName, String permName,
+ boolean removeAllowlistedRestrictedPermission(String packageName, String permissionName,
int flags, int userId);
void grantRuntimePermission(String packageName, String permName, int userId);
@@ -87,7 +87,7 @@
List<String> getAutoRevokeExemptionGrantedPackages(int userId);
- boolean setAutoRevokeWhitelisted(String packageName, boolean whitelisted, int userId);
+ boolean setAutoRevokeExempted(String packageName, boolean exempted, int userId);
- boolean isAutoRevokeWhitelisted(String packageName, int userId);
+ boolean isAutoRevokeExempted(String packageName, int userId);
}
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index d31e012..87f3764 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -510,7 +510,7 @@
public Set<String> getAllowlistedRestrictedPermissions(@NonNull String packageName,
@PackageManager.PermissionWhitelistFlags int allowlistFlag) {
try {
- final List<String> allowlist = mPermissionManager.getWhitelistedRestrictedPermissions(
+ final List<String> allowlist = mPermissionManager.getAllowlistedRestrictedPermissions(
packageName, allowlistFlag, mContext.getUserId());
if (allowlist == null) {
return Collections.emptySet();
@@ -578,7 +578,7 @@
@NonNull String permissionName,
@PackageManager.PermissionWhitelistFlags int allowlistFlags) {
try {
- return mPermissionManager.addWhitelistedRestrictedPermission(packageName,
+ return mPermissionManager.addAllowlistedRestrictedPermission(packageName,
permissionName, allowlistFlags, mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -642,7 +642,7 @@
@NonNull String permissionName,
@PackageManager.PermissionWhitelistFlags int allowlistFlags) {
try {
- return mPermissionManager.removeWhitelistedRestrictedPermission(packageName,
+ return mPermissionManager.removeAllowlistedRestrictedPermission(packageName,
permissionName, allowlistFlags, mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -668,7 +668,7 @@
conditional = true)
public boolean isAutoRevokeExempted(@NonNull String packageName) {
try {
- return mPermissionManager.isAutoRevokeWhitelisted(packageName, mContext.getUserId());
+ return mPermissionManager.isAutoRevokeExempted(packageName, mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -697,7 +697,7 @@
conditional = true)
public boolean setAutoRevokeExempted(@NonNull String packageName, boolean exempted) {
try {
- return mPermissionManager.setAutoRevokeWhitelisted(packageName, exempted,
+ return mPermissionManager.setAutoRevokeExempted(packageName, exempted,
mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index b2b8db1..376d942 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -4313,13 +4313,23 @@
* <P>
* Type: INTEGER (A bitmask of CARRIER_PRESENCE_* fields)
* </P>
+ *
+ * @deprecated The contacts database will only show presence
+ * information on devices where
+ * {@link android.telephony.CarrierConfigManager#KEY_USE_RCS_PRESENCE_BOOL} is true,
+ * otherwise use {@link android.telephony.ims.RcsUceAdapter}.
*/
+ @Deprecated
public static final String CARRIER_PRESENCE = "carrier_presence";
/**
* Indicates that the entry is Video Telephony (VT) capable on the
* current carrier. An allowed bitmask of {@link #CARRIER_PRESENCE}.
+ *
+ * @deprecated Same as {@link DataColumns#CARRIER_PRESENCE}.
+ *
*/
+ @Deprecated
public static final int CARRIER_PRESENCE_VT_CAPABLE = 0x01;
/**
diff --git a/core/java/android/service/attestation/OWNERS b/core/java/android/service/attestation/OWNERS
new file mode 100644
index 0000000..b9e7b99
--- /dev/null
+++ b/core/java/android/service/attestation/OWNERS
@@ -0,0 +1,2 @@
+chaviw@google.com
+ogunwale@google.com
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 1f15d46..4a48832 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -402,6 +402,10 @@
}
} else if (autoCorrection) {
tp.setUnderlineText(mAutoCorrectionUnderlineColor, mAutoCorrectionUnderlineThickness);
+ } else if (misspelled) {
+ tp.setUnderlineText(mMisspelledUnderlineColor, mMisspelledUnderlineThickness);
+ } else if (grammarError) {
+ tp.setUnderlineText(mGrammarErrorUnderlineColor, mGrammarErrorUnderlineThickness);
}
}
@@ -425,6 +429,10 @@
}
} else if (autoCorrection) {
return mAutoCorrectionUnderlineColor;
+ } else if (misspelled) {
+ return mMisspelledUnderlineColor;
+ } else if (grammarError) {
+ return mGrammarErrorUnderlineColor;
}
return 0;
}
diff --git a/core/java/android/util/Xml.java b/core/java/android/util/Xml.java
index c8193b3..38decf9 100644
--- a/core/java/android/util/Xml.java
+++ b/core/java/android/util/Xml.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.SystemProperties;
import android.system.ErrnoException;
import android.system.Os;
@@ -64,8 +65,11 @@
/**
* Feature flag: when set, {@link #resolveSerializer(OutputStream)} will
* emit binary XML by default.
+ *
+ * @hide
*/
- private static final boolean ENABLE_BINARY_DEFAULT = false;
+ public static final boolean ENABLE_BINARY_DEFAULT = SystemProperties
+ .getBoolean("persist.sys.binary_xml", true);
/**
* Parses the given xml string and fires events on the given SAX handler.
@@ -172,7 +176,7 @@
if (!in.markSupported()) {
in = new BufferedInputStream(in);
}
- in.mark(4);
+ in.mark(8);
in.read(magic);
in.reset();
}
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 2e90619..9473845 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -113,8 +113,6 @@
private AddNodeInfosForViewId mAddNodeInfosForViewId;
- private List<Message> mPendingFindNodeByIdMessages;
-
@GuardedBy("mLock")
private int mNumActiveRequestPreparers;
@GuardedBy("mLock")
@@ -130,7 +128,6 @@
mViewRootImpl = viewRootImpl;
mPrefetcher = new AccessibilityNodePrefetcher();
mA11yManager = mViewRootImpl.mContext.getSystemService(AccessibilityManager.class);
- mPendingFindNodeByIdMessages = new ArrayList<>();
}
private void scheduleMessage(Message message, int interrogatingPid, long interrogatingTid,
@@ -180,7 +177,6 @@
args.arg4 = arguments;
message.obj = args;
- mPendingFindNodeByIdMessages.add(message);
scheduleMessage(message, interrogatingPid, interrogatingTid, CONSIDER_REQUEST_PREPARERS);
}
@@ -319,8 +315,6 @@
}
private void findAccessibilityNodeInfoByAccessibilityIdUiThread(Message message) {
- mPendingFindNodeByIdMessages.remove(message);
-
final int flags = message.arg1;
SomeArgs args = (SomeArgs) message.obj;
@@ -335,58 +329,22 @@
args.recycle();
- View rootView = null;
- AccessibilityNodeInfo rootNode = null;
+ List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
+ infos.clear();
try {
if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) {
return;
}
mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags;
- rootView = findViewByAccessibilityId(accessibilityViewId);
- if (rootView != null && isShown(rootView)) {
- rootNode = populateAccessibilityNodeInfoForView(
- rootView, arguments, virtualDescendantId);
+ final View root = findViewByAccessibilityId(accessibilityViewId);
+ if (root != null && isShown(root)) {
+ mPrefetcher.prefetchAccessibilityNodeInfos(
+ root, virtualDescendantId, flags, infos, arguments);
}
} finally {
- updateInfoForViewportAndReturnFindNodeResult(
- rootNode == null ? null : AccessibilityNodeInfo.obtain(rootNode),
- callback, interactionId, spec, interactiveRegion);
+ updateInfosForViewportAndReturnFindNodeResult(
+ infos, callback, interactionId, spec, interactiveRegion);
}
- List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
- infos.clear();
- mPrefetcher.prefetchAccessibilityNodeInfos(
- rootView, rootNode == null ? null : AccessibilityNodeInfo.obtain(rootNode),
- virtualDescendantId, flags, infos);
- mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
- updateInfosForViewPort(infos, spec, interactiveRegion);
- returnPrefetchResult(interactionId, infos, callback);
- returnPendingFindAccessibilityNodeInfosInPrefetch(infos);
- }
-
- private AccessibilityNodeInfo populateAccessibilityNodeInfoForView(
- View view, Bundle arguments, int virtualViewId) {
- AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider();
- // Determine if we'll be populating extra data
- final String extraDataRequested = (arguments == null) ? null
- : arguments.getString(EXTRA_DATA_REQUESTED_KEY);
- AccessibilityNodeInfo root = null;
- if (provider == null) {
- root = view.createAccessibilityNodeInfo();
- if (root != null) {
- if (extraDataRequested != null) {
- view.addExtraDataToAccessibilityNodeInfo(root, extraDataRequested, arguments);
- }
- }
- } else {
- root = provider.createAccessibilityNodeInfo(virtualViewId);
- if (root != null) {
- if (extraDataRequested != null) {
- provider.addExtraDataToAccessibilityNodeInfo(
- virtualViewId, root, extraDataRequested, arguments);
- }
- }
- }
- return root;
}
public void findAccessibilityNodeInfosByViewIdClientThread(long accessibilityNodeId,
@@ -444,7 +402,6 @@
mAddNodeInfosForViewId.reset();
}
} finally {
- mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
updateInfosForViewportAndReturnFindNodeResult(
infos, callback, interactionId, spec, interactiveRegion);
}
@@ -527,7 +484,6 @@
}
}
} finally {
- mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
updateInfosForViewportAndReturnFindNodeResult(
infos, callback, interactionId, spec, interactiveRegion);
}
@@ -619,7 +575,6 @@
}
}
} finally {
- mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
updateInfoForViewportAndReturnFindNodeResult(
focused, callback, interactionId, spec, interactiveRegion);
}
@@ -674,7 +629,6 @@
}
}
} finally {
- mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
updateInfoForViewportAndReturnFindNodeResult(
next, callback, interactionId, spec, interactiveRegion);
}
@@ -831,6 +785,33 @@
}
}
+ private void applyAppScaleAndMagnificationSpecIfNeeded(List<AccessibilityNodeInfo> infos,
+ MagnificationSpec spec) {
+ if (infos == null) {
+ return;
+ }
+ final float applicationScale = mViewRootImpl.mAttachInfo.mApplicationScale;
+ if (shouldApplyAppScaleAndMagnificationSpec(applicationScale, spec)) {
+ final int infoCount = infos.size();
+ for (int i = 0; i < infoCount; i++) {
+ AccessibilityNodeInfo info = infos.get(i);
+ applyAppScaleAndMagnificationSpecIfNeeded(info, spec);
+ }
+ }
+ }
+
+ private void adjustIsVisibleToUserIfNeeded(List<AccessibilityNodeInfo> infos,
+ Region interactiveRegion) {
+ if (interactiveRegion == null || infos == null) {
+ return;
+ }
+ final int infoCount = infos.size();
+ for (int i = 0; i < infoCount; i++) {
+ AccessibilityNodeInfo info = infos.get(i);
+ adjustIsVisibleToUserIfNeeded(info, interactiveRegion);
+ }
+ }
+
private void adjustIsVisibleToUserIfNeeded(AccessibilityNodeInfo info,
Region interactiveRegion) {
if (interactiveRegion == null || info == null) {
@@ -851,6 +832,17 @@
return false;
}
+ private void adjustBoundsInScreenIfNeeded(List<AccessibilityNodeInfo> infos) {
+ if (infos == null || shouldBypassAdjustBoundsInScreen()) {
+ return;
+ }
+ final int infoCount = infos.size();
+ for (int i = 0; i < infoCount; i++) {
+ final AccessibilityNodeInfo info = infos.get(i);
+ adjustBoundsInScreenIfNeeded(info);
+ }
+ }
+
private void adjustBoundsInScreenIfNeeded(AccessibilityNodeInfo info) {
if (info == null || shouldBypassAdjustBoundsInScreen()) {
return;
@@ -898,6 +890,17 @@
return screenMatrix == null || screenMatrix.isIdentity();
}
+ private void associateLeashedParentIfNeeded(List<AccessibilityNodeInfo> infos) {
+ if (infos == null || shouldBypassAssociateLeashedParent()) {
+ return;
+ }
+ final int infoCount = infos.size();
+ for (int i = 0; i < infoCount; i++) {
+ final AccessibilityNodeInfo info = infos.get(i);
+ associateLeashedParentIfNeeded(info);
+ }
+ }
+
private void associateLeashedParentIfNeeded(AccessibilityNodeInfo info) {
if (info == null || shouldBypassAssociateLeashedParent()) {
return;
@@ -971,46 +974,18 @@
return (appScale != 1.0f || (spec != null && !spec.isNop()));
}
- private void updateInfosForViewPort(List<AccessibilityNodeInfo> infos, MagnificationSpec spec,
- Region interactiveRegion) {
- for (int i = 0; i < infos.size(); i++) {
- updateInfoForViewPort(infos.get(i), spec, interactiveRegion);
- }
- }
-
- private void updateInfoForViewPort(AccessibilityNodeInfo info, MagnificationSpec spec,
- Region interactiveRegion) {
- associateLeashedParentIfNeeded(info);
- applyScreenMatrixIfNeeded(info);
- adjustBoundsInScreenIfNeeded(info);
- // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node,
- // then impact the visibility result, we need to adjust visibility before apply scale.
- adjustIsVisibleToUserIfNeeded(info, interactiveRegion);
- applyAppScaleAndMagnificationSpecIfNeeded(info, spec);
- }
-
private void updateInfosForViewportAndReturnFindNodeResult(List<AccessibilityNodeInfo> infos,
IAccessibilityInteractionConnectionCallback callback, int interactionId,
MagnificationSpec spec, Region interactiveRegion) {
- if (infos != null) {
- updateInfosForViewPort(infos, spec, interactiveRegion);
- }
- returnFindNodesResult(infos, callback, interactionId);
- }
-
- private void returnFindNodeResult(AccessibilityNodeInfo info,
- IAccessibilityInteractionConnectionCallback callback,
- int interactionId) {
try {
- callback.setFindAccessibilityNodeInfoResult(info, interactionId);
- } catch (RemoteException re) {
- /* ignore - the other side will time out */
- }
- }
-
- private void returnFindNodesResult(List<AccessibilityNodeInfo> infos,
- IAccessibilityInteractionConnectionCallback callback, int interactionId) {
- try {
+ mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
+ associateLeashedParentIfNeeded(infos);
+ applyScreenMatrixIfNeeded(infos);
+ adjustBoundsInScreenIfNeeded(infos);
+ // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node,
+ // then impact the visibility result, we need to adjust visibility before apply scale.
+ adjustIsVisibleToUserIfNeeded(infos, interactiveRegion);
+ applyAppScaleAndMagnificationSpecIfNeeded(infos, spec);
callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
if (infos != null) {
infos.clear();
@@ -1020,49 +995,22 @@
}
}
- private void returnPendingFindAccessibilityNodeInfosInPrefetch(
- List<AccessibilityNodeInfo> infos) {
- for (Message pendingMessage : mPendingFindNodeByIdMessages) {
- SomeArgs args = (SomeArgs) pendingMessage.obj;
- final int accessibilityViewId = args.argi1;
- final int virtualDescendantId = args.argi2;
- final int interactionId = args.argi3;
- final IAccessibilityInteractionConnectionCallback callback =
- (IAccessibilityInteractionConnectionCallback) args.arg1;
- final long nodeId =
- AccessibilityNodeInfo.makeNodeId(accessibilityViewId, virtualDescendantId);
- for (int i = 0; i < infos.size(); i++) {
- AccessibilityNodeInfo info = infos.get(i);
- if (info.getSourceNodeId() == nodeId) {
- returnFindNodeResult(
- AccessibilityNodeInfo.obtain(info), callback, interactionId);
- mHandler.removeMessages(
- PrivateHandler.MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID,
- pendingMessage.obj);
- args.recycle();
- break;
- }
- }
- }
- mPendingFindNodeByIdMessages.clear();
- }
-
- private void returnPrefetchResult(int interactionId, List<AccessibilityNodeInfo> infos,
- IAccessibilityInteractionConnectionCallback callback) {
- if (infos.size() > 0) {
- try {
- callback.setPrefetchAccessibilityNodeInfoResult(infos, interactionId);
- } catch (RemoteException re) {
- /* ignore - other side isn't too bothered if this doesn't arrive */
- }
- }
- }
-
private void updateInfoForViewportAndReturnFindNodeResult(AccessibilityNodeInfo info,
IAccessibilityInteractionConnectionCallback callback, int interactionId,
MagnificationSpec spec, Region interactiveRegion) {
- updateInfoForViewPort(info, spec, interactiveRegion);
- returnFindNodeResult(info, callback, interactionId);
+ try {
+ mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
+ associateLeashedParentIfNeeded(info);
+ applyScreenMatrixIfNeeded(info);
+ adjustBoundsInScreenIfNeeded(info);
+ // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node,
+ // then impact the visibility result, we need to adjust visibility before apply scale.
+ adjustIsVisibleToUserIfNeeded(info, interactiveRegion);
+ applyAppScaleAndMagnificationSpecIfNeeded(info, spec);
+ callback.setFindAccessibilityNodeInfoResult(info, interactionId);
+ } catch (RemoteException re) {
+ /* ignore - the other side will time out */
+ }
}
private boolean handleClickableSpanActionUiThread(
@@ -1105,11 +1053,20 @@
private final ArrayList<View> mTempViewList = new ArrayList<View>();
- public void prefetchAccessibilityNodeInfos(View view, AccessibilityNodeInfo root,
- int virtualViewId, int fetchFlags, List<AccessibilityNodeInfo> outInfos) {
- if (root != null) {
- AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider();
- if (provider == null) {
+ public void prefetchAccessibilityNodeInfos(View view, int virtualViewId, int fetchFlags,
+ List<AccessibilityNodeInfo> outInfos, Bundle arguments) {
+ AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider();
+ // Determine if we'll be populating extra data
+ final String extraDataRequested = (arguments == null) ? null
+ : arguments.getString(EXTRA_DATA_REQUESTED_KEY);
+ if (provider == null) {
+ AccessibilityNodeInfo root = view.createAccessibilityNodeInfo();
+ if (root != null) {
+ if (extraDataRequested != null) {
+ view.addExtraDataToAccessibilityNodeInfo(
+ root, extraDataRequested, arguments);
+ }
+ outInfos.add(root);
if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) {
prefetchPredecessorsOfRealNode(view, outInfos);
}
@@ -1119,7 +1076,16 @@
if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS) != 0) {
prefetchDescendantsOfRealNode(view, outInfos);
}
- } else {
+ }
+ } else {
+ final AccessibilityNodeInfo root =
+ provider.createAccessibilityNodeInfo(virtualViewId);
+ if (root != null) {
+ if (extraDataRequested != null) {
+ provider.addExtraDataToAccessibilityNodeInfo(
+ virtualViewId, root, extraDataRequested, arguments);
+ }
+ outInfos.add(root);
if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) {
prefetchPredecessorsOfVirtualNode(root, view, provider, outInfos);
}
@@ -1130,19 +1096,13 @@
prefetchDescendantsOfVirtualNode(root, provider, outInfos);
}
}
- if (ENFORCE_NODE_TREE_CONSISTENT) {
- enforceNodeTreeConsistent(root, outInfos);
- }
+ }
+ if (ENFORCE_NODE_TREE_CONSISTENT) {
+ enforceNodeTreeConsistent(outInfos);
}
}
- private boolean shouldStopPrefetching(List prefetchededInfos) {
- return mHandler.hasUserInteractiveMessagesWaiting()
- || prefetchededInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE;
- }
-
- private void enforceNodeTreeConsistent(
- AccessibilityNodeInfo root, List<AccessibilityNodeInfo> nodes) {
+ private void enforceNodeTreeConsistent(List<AccessibilityNodeInfo> nodes) {
LongSparseArray<AccessibilityNodeInfo> nodeMap =
new LongSparseArray<AccessibilityNodeInfo>();
final int nodeCount = nodes.size();
@@ -1153,6 +1113,7 @@
// If the nodes are a tree it does not matter from
// which node we start to search for the root.
+ AccessibilityNodeInfo root = nodeMap.valueAt(0);
AccessibilityNodeInfo parent = root;
while (parent != null) {
root = parent;
@@ -1219,11 +1180,9 @@
private void prefetchPredecessorsOfRealNode(View view,
List<AccessibilityNodeInfo> outInfos) {
- if (shouldStopPrefetching(outInfos)) {
- return;
- }
ViewParent parent = view.getParentForAccessibility();
- while (parent instanceof View && !shouldStopPrefetching(outInfos)) {
+ while (parent instanceof View
+ && outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
View parentView = (View) parent;
AccessibilityNodeInfo info = parentView.createAccessibilityNodeInfo();
if (info != null) {
@@ -1235,9 +1194,6 @@
private void prefetchSiblingsOfRealNode(View current,
List<AccessibilityNodeInfo> outInfos) {
- if (shouldStopPrefetching(outInfos)) {
- return;
- }
ViewParent parent = current.getParentForAccessibility();
if (parent instanceof ViewGroup) {
ViewGroup parentGroup = (ViewGroup) parent;
@@ -1247,7 +1203,7 @@
parentGroup.addChildrenForAccessibility(children);
final int childCount = children.size();
for (int i = 0; i < childCount; i++) {
- if (shouldStopPrefetching(outInfos)) {
+ if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
return;
}
View child = children.get(i);
@@ -1275,7 +1231,7 @@
private void prefetchDescendantsOfRealNode(View root,
List<AccessibilityNodeInfo> outInfos) {
- if (shouldStopPrefetching(outInfos) || !(root instanceof ViewGroup)) {
+ if (!(root instanceof ViewGroup)) {
return;
}
HashMap<View, AccessibilityNodeInfo> addedChildren =
@@ -1286,7 +1242,7 @@
root.addChildrenForAccessibility(children);
final int childCount = children.size();
for (int i = 0; i < childCount; i++) {
- if (shouldStopPrefetching(outInfos)) {
+ if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
return;
}
View child = children.get(i);
@@ -1311,7 +1267,7 @@
} finally {
children.clear();
}
- if (!shouldStopPrefetching(outInfos)) {
+ if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
for (Map.Entry<View, AccessibilityNodeInfo> entry : addedChildren.entrySet()) {
View addedChild = entry.getKey();
AccessibilityNodeInfo virtualRoot = entry.getValue();
@@ -1333,7 +1289,7 @@
long parentNodeId = root.getParentNodeId();
int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(parentNodeId);
while (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
- if (shouldStopPrefetching(outInfos)) {
+ if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
return;
}
final int virtualDescendantId =
@@ -1378,7 +1334,7 @@
if (parent != null) {
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
- if (shouldStopPrefetching(outInfos)) {
+ if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
return;
}
final long childNodeId = parent.getChildId(i);
@@ -1403,7 +1359,7 @@
final int initialOutInfosSize = outInfos.size();
final int childCount = root.getChildCount();
for (int i = 0; i < childCount; i++) {
- if (shouldStopPrefetching(outInfos)) {
+ if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
return;
}
final long childNodeId = root.getChildId(i);
@@ -1413,7 +1369,7 @@
outInfos.add(child);
}
}
- if (!shouldStopPrefetching(outInfos)) {
+ if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
final int addedChildCount = outInfos.size() - initialOutInfosSize;
for (int i = 0; i < addedChildCount; i++) {
AccessibilityNodeInfo child = outInfos.get(initialOutInfosSize + i);
@@ -1522,10 +1478,6 @@
boolean hasAccessibilityCallback(Message message) {
return message.what < FIRST_NO_ACCESSIBILITY_CALLBACK_MSG ? true : false;
}
-
- boolean hasUserInteractiveMessagesWaiting() {
- return hasMessagesOrCallbacks();
- }
}
private final class AddNodeInfosForViewId implements Predicate<View> {
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index e685b30..fb012eb 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -130,11 +130,6 @@
void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId);
/**
- * Tell the window that it is either gaining or losing pointer capture.
- */
- void dispatchPointerCaptureChanged(boolean hasCapture);
-
- /**
* Called when Scroll Capture support is requested for a window.
*
* @param callbacks to receive responses
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index df96dc3..f4b90e1 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -22,6 +22,7 @@
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
+import android.hardware.SensorManager;
import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.InputManager;
import android.os.Build;
@@ -71,13 +72,18 @@
private final boolean mHasVibrator;
private final boolean mHasMicrophone;
private final boolean mHasButtonUnderPad;
+ private final boolean mHasSensor;
private final ArrayList<MotionRange> mMotionRanges = new ArrayList<MotionRange>();
+ @GuardedBy("mMotionRanges")
private Vibrator mVibrator; // guarded by mMotionRanges during initialization
@GuardedBy("mMotionRanges")
private VibratorManager mVibratorManager;
+ @GuardedBy("mMotionRanges")
+ private SensorManager mSensorManager;
+
/**
* A mask for input source classes.
*
@@ -442,7 +448,7 @@
public InputDevice(int id, int generation, int controllerNumber, String name, int vendorId,
int productId, String descriptor, boolean isExternal, int sources, int keyboardType,
KeyCharacterMap keyCharacterMap, boolean hasVibrator, boolean hasMicrophone,
- boolean hasButtonUnderPad) {
+ boolean hasButtonUnderPad, boolean hasSensor) {
mId = id;
mGeneration = generation;
mControllerNumber = controllerNumber;
@@ -457,10 +463,12 @@
mHasVibrator = hasVibrator;
mHasMicrophone = hasMicrophone;
mHasButtonUnderPad = hasButtonUnderPad;
+ mHasSensor = hasSensor;
mIdentifier = new InputDeviceIdentifier(descriptor, vendorId, productId);
}
private InputDevice(Parcel in) {
+ mKeyCharacterMap = KeyCharacterMap.CREATOR.createFromParcel(in);
mId = in.readInt();
mGeneration = in.readInt();
mControllerNumber = in.readInt();
@@ -471,10 +479,10 @@
mIsExternal = in.readInt() != 0;
mSources = in.readInt();
mKeyboardType = in.readInt();
- mKeyCharacterMap = KeyCharacterMap.CREATOR.createFromParcel(in);
mHasVibrator = in.readInt() != 0;
mHasMicrophone = in.readInt() != 0;
mHasButtonUnderPad = in.readInt() != 0;
+ mHasSensor = in.readInt() != 0;
mIdentifier = new InputDeviceIdentifier(mDescriptor, mVendorId, mProductId);
int numRanges = in.readInt();
@@ -822,6 +830,26 @@
}
/**
+ * Gets the sensor manager service associated with the input device.
+ * Even if the device does not have a sensor, the result is never null.
+ * Use {@link SensorManager#getSensorList} to get a full list of all supported sensors.
+ *
+ * Note that the sensors associated with the device may be different from
+ * the system sensors, as typically they are builtin sensors physically attached to
+ * input devices.
+ *
+ * @return The sensor manager service associated with the device, never null.
+ */
+ public @NonNull SensorManager getSensorManager() {
+ synchronized (mMotionRanges) {
+ if (mSensorManager == null) {
+ mSensorManager = InputManager.getInstance().getInputDeviceSensorManager(mId);
+ }
+ }
+ return mSensorManager;
+ }
+
+ /**
* Returns true if input device is enabled.
* @return Whether the input device is enabled.
*/
@@ -869,6 +897,15 @@
}
/**
+ * Reports whether the device has a sensor.
+ * @return Whether the device has a sensor.
+ * @hide
+ */
+ public boolean hasSensor() {
+ return mHasSensor;
+ }
+
+ /**
* Sets the current pointer type.
* @param pointerType the type of the pointer icon.
* @hide
@@ -999,6 +1036,7 @@
@Override
public void writeToParcel(Parcel out, int flags) {
+ mKeyCharacterMap.writeToParcel(out, flags);
out.writeInt(mId);
out.writeInt(mGeneration);
out.writeInt(mControllerNumber);
@@ -1009,10 +1047,10 @@
out.writeInt(mIsExternal ? 1 : 0);
out.writeInt(mSources);
out.writeInt(mKeyboardType);
- mKeyCharacterMap.writeToParcel(out, flags);
out.writeInt(mHasVibrator ? 1 : 0);
out.writeInt(mHasMicrophone ? 1 : 0);
out.writeInt(mHasButtonUnderPad ? 1 : 0);
+ out.writeInt(mHasSensor ? 1 : 0);
final int numRanges = mMotionRanges.size();
out.writeInt(numRanges);
@@ -1057,6 +1095,8 @@
description.append(" Has Vibrator: ").append(mHasVibrator).append("\n");
+ description.append(" Has Sensor: ").append(mHasSensor).append("\n");
+
description.append(" Has mic: ").append(mHasMicrophone).append("\n");
description.append(" Sources: 0x").append(Integer.toHexString(mSources)).append(" (");
diff --git a/core/java/android/view/ScrollCaptureTargetResolver.java b/core/java/android/view/ScrollCaptureTargetResolver.java
index 5106534..e4316bb 100644
--- a/core/java/android/view/ScrollCaptureTargetResolver.java
+++ b/core/java/android/view/ScrollCaptureTargetResolver.java
@@ -182,9 +182,8 @@
}
mResult = chooseTarget(mResult, target);
boolean finish = mPendingBoundsRequests == 0
- || SystemClock.elapsedRealtime() >= mDeadlineMillis;
+ || SystemClock.uptimeMillis() >= mDeadlineMillis;
if (finish) {
- System.err.println("We think we're done, or timed out");
mPendingBoundsRequests = 0;
mWhenComplete.accept(mResult);
synchronized (mLock) {
@@ -233,7 +232,7 @@
for (ScrollCaptureTarget target : mTargets) {
queryTarget(target);
}
- mDeadlineMillis = SystemClock.elapsedRealtime() + mTimeLimitMillis;
+ mDeadlineMillis = SystemClock.uptimeMillis() + mTimeLimitMillis;
mHandler.postAtTime(mTimeoutRunnable, mDeadlineMillis);
}
@@ -275,7 +274,7 @@
mHandler.removeCallbacks(mTimeoutRunnable);
boolean doneOrTimedOut = mPendingBoundsRequests == 0
- || SystemClock.elapsedRealtime() >= mDeadlineMillis;
+ || SystemClock.uptimeMillis() >= mDeadlineMillis;
final View containingView = target.getContainingView();
if (!nullOrEmpty(scrollBounds) && containingView.isAggregatedVisible()) {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index f05e671..b5185ae 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -240,7 +240,7 @@
private static boolean useBlastAdapter(Context context) {
ContentResolver contentResolver = context.getContentResolver();
return Settings.Global.getInt(contentResolver,
- Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_SV, 0 /* default */) == 1;
+ Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_SV, 1 /* default */) == 1;
}
private final boolean mUseBlastAdapter;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index d24380b..52ce5e7 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -8665,7 +8665,7 @@
MSG_REQUEST_KEYBOARD_SHORTCUTS, deviceId, 0, receiver).sendToTarget();
}
- public void dispatchPointerCaptureChanged(boolean on) {
+ private void dispatchPointerCaptureChanged(boolean on) {
final int what = MSG_POINTER_CAPTURE_CHANGED;
mHandler.removeMessages(what);
Message msg = mHandler.obtainMessage(what);
@@ -9438,14 +9438,6 @@
}
@Override
- public void dispatchPointerCaptureChanged(boolean hasCapture) {
- final ViewRootImpl viewAncestor = mViewAncestor.get();
- if (viewAncestor != null) {
- viewAncestor.dispatchPointerCaptureChanged(hasCapture);
- }
- }
-
- @Override
public void requestScrollCapture(IScrollCaptureCallbacks callbacks) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index aff0b35..f63749b 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -23,9 +23,7 @@
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
-import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
@@ -125,12 +123,6 @@
private Message mSameThreadMessage;
- private int mInteractionIdWaitingForPrefetchResult;
- private int mConnectionIdWaitingForPrefetchResult;
- private String[] mPackageNamesForNextPrefetchResult;
- private final Handler mMainHandler;
- private Runnable mPrefetchResultRunnable;
-
/**
* @return The client for the current thread.
*/
@@ -205,7 +197,6 @@
private AccessibilityInteractionClient() {
/* reducing constructor visibility */
- mMainHandler = new Handler(Looper.getMainLooper());
}
/**
@@ -460,16 +451,16 @@
Binder.restoreCallingIdentity(identityToken);
}
if (packageNames != null) {
- AccessibilityNodeInfo info =
- getFindAccessibilityNodeInfoResultAndClear(interactionId);
- if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_MASK) != 0
- && info != null) {
- setInteractionWaitingForPrefetchResult(interactionId, connectionId,
- packageNames);
- }
- finalizeAndCacheAccessibilityNodeInfo(info, connectionId,
+ List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
+ interactionId);
+ finalizeAndCacheAccessibilityNodeInfos(infos, connectionId,
bypassCache, packageNames);
- return info;
+ if (infos != null && !infos.isEmpty()) {
+ for (int i = 1; i < infos.size(); i++) {
+ infos.get(i).recycle();
+ }
+ return infos.get(0);
+ }
}
} else {
if (DEBUG) {
@@ -483,15 +474,6 @@
return null;
}
- private void setInteractionWaitingForPrefetchResult(int interactionId, int connectionId,
- String[] packageNames) {
- synchronized (mInstanceLock) {
- mInteractionIdWaitingForPrefetchResult = interactionId;
- mConnectionIdWaitingForPrefetchResult = connectionId;
- mPackageNamesForNextPrefetchResult = packageNames;
- }
- }
-
private static String idToString(int accessibilityWindowId, long accessibilityNodeId) {
return accessibilityWindowId + "/"
+ AccessibilityNodeInfo.idToString(accessibilityNodeId);
@@ -847,26 +829,6 @@
}
/**
- * {@inheritDoc}
- */
- @Override
- public void setPrefetchAccessibilityNodeInfoResult(List<AccessibilityNodeInfo> infos,
- int interactionId) {
- synchronized (mInstanceLock) {
- if (mPrefetchResultRunnable != null) {
- mMainHandler.removeCallbacks(mPrefetchResultRunnable);
- mPrefetchResultRunnable = null;
- }
- if (!infos.isEmpty() && mInteractionIdWaitingForPrefetchResult == interactionId) {
- mPrefetchResultRunnable = () -> finalizeAndCacheAccessibilityNodeInfos(
- infos, mConnectionIdWaitingForPrefetchResult, false,
- mPackageNamesForNextPrefetchResult);
- mMainHandler.post(mPrefetchResultRunnable);
- }
- }
- }
-
- /**
* Gets the result of a request to perform an accessibility action.
*
* @param interactionId The interaction id to match the result with the request.
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
index 231e75a..049bb31 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
@@ -47,15 +47,6 @@
int interactionId);
/**
- * Sets the result of a prefetch request that returns {@link AccessibilityNodeInfo}s.
- *
- * @param root The {@link AccessibilityNodeInfo} for which the prefetching is based off of.
- * @param infos The result {@link AccessibilityNodeInfo}s.
- */
- void setPrefetchAccessibilityNodeInfoResult(
- in List<AccessibilityNodeInfo> infos, int interactionId);
-
- /**
* Sets the result of a request to perform an accessibility action.
*
* @param Whether the action was performed.
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index 7dbf693..1cf25a7 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -28,6 +28,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.content.res.Configuration;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.LocaleList;
@@ -293,6 +294,13 @@
public static final int IME_FLAG_FORCE_ASCII = 0x80000000;
/**
+ * Flag of {@link #internalImeOptions}: flag is set when app window containing this
+ * {@link EditorInfo} is using {@link Configuration#ORIENTATION_PORTRAIT} mode.
+ * @hide
+ */
+ public static final int IME_FLAG_APP_WINDOW_PORTRAIT = 0x80000000;
+
+ /**
* Generic unspecified type for {@link #imeOptions}.
*/
public static final int IME_NULL = 0x00000000;
@@ -312,6 +320,7 @@
* 1 1 IME_ACTION_NEXT
* 11 IME_ACTION_DONE
* 111 IME_ACTION_PREVIOUS
+ * 1 IME_FLAG_APP_WINDOW_PORTRAIT
* 1 IME_FLAG_NO_PERSONALIZED_LEARNING
* 1 IME_FLAG_NO_FULLSCREEN
* 1 IME_FLAG_NAVIGATE_PREVIOUS
@@ -343,6 +352,20 @@
public String privateImeOptions = null;
/**
+ * Masks for {@link internalImeOptions}
+ *
+ * <pre>
+ * 1 IME_FLAG_APP_WINDOW_PORTRAIT
+ * |-------|-------|-------|-------|</pre>
+ */
+
+ /**
+ * Same as {@link android.R.attr#imeOptions} but for framework's internal-use only.
+ * @hide
+ */
+ public int internalImeOptions = IME_NULL;
+
+ /**
* In some cases an IME may be able to display an arbitrary label for
* a command the user can perform, which you can specify here. This is
* typically used as the label for the action to use in-line as a replacement
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 6526b8c..0a4b784 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1361,7 +1361,9 @@
// We intentionally do not use UserHandle.getCallingUserId() here because for system
// services InputMethodManagerInternal.getInputMethodListAsUser() should be used
// instead.
- return mService.getInputMethodList(UserHandle.myUserId());
+ final Completable.InputMethodInfoList value = Completable.createInputMethodInfoList();
+ mService.getInputMethodList(UserHandle.myUserId(), ResultCallbacks.of(value));
+ return Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1377,7 +1379,9 @@
@RequiresPermission(INTERACT_ACROSS_USERS_FULL)
public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
try {
- return mService.getInputMethodList(userId);
+ final Completable.InputMethodInfoList value = Completable.createInputMethodInfoList();
+ mService.getInputMethodList(userId, ResultCallbacks.of(value));
+ return Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1395,7 +1399,9 @@
// We intentionally do not use UserHandle.getCallingUserId() here because for system
// services InputMethodManagerInternal.getEnabledInputMethodListAsUser() should be used
// instead.
- return mService.getEnabledInputMethodList(UserHandle.myUserId());
+ final Completable.InputMethodInfoList value = Completable.createInputMethodInfoList();
+ mService.getEnabledInputMethodList(UserHandle.myUserId(), ResultCallbacks.of(value));
+ return Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1411,7 +1417,9 @@
@RequiresPermission(INTERACT_ACROSS_USERS_FULL)
public List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
try {
- return mService.getEnabledInputMethodList(userId);
+ final Completable.InputMethodInfoList value = Completable.createInputMethodInfoList();
+ mService.getEnabledInputMethodList(userId, ResultCallbacks.of(value));
+ return Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1430,8 +1438,13 @@
public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo imi,
boolean allowsImplicitlySelectedSubtypes) {
try {
- return mService.getEnabledInputMethodSubtypeList(
- imi == null ? null : imi.getId(), allowsImplicitlySelectedSubtypes);
+ final Completable.InputMethodSubtypeList value =
+ Completable.createInputMethodSubtypeList();
+ mService.getEnabledInputMethodSubtypeList(
+ imi == null ? null : imi.getId(),
+ allowsImplicitlySelectedSubtypes,
+ ResultCallbacks.of(value));
+ return Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2970,7 +2983,9 @@
*/
public InputMethodSubtype getCurrentInputMethodSubtype() {
try {
- return mService.getCurrentInputMethodSubtype();
+ final Completable.InputMethodSubtype value = Completable.createInputMethodSubtype();
+ mService.getCurrentInputMethodSubtype(ResultCallbacks.of(value));
+ return Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3019,7 +3034,11 @@
}
final List<InputMethodSubtype> enabledSubtypes;
try {
- enabledSubtypes = mService.getEnabledInputMethodSubtypeList(imeId, true);
+ final Completable.InputMethodSubtypeList value =
+ Completable.createInputMethodSubtypeList();
+ mService.getEnabledInputMethodSubtypeList(
+ imeId, true, ResultCallbacks.of(value));
+ enabledSubtypes = Completable.getResult(value);
} catch (RemoteException e) {
return false;
}
@@ -3087,7 +3106,9 @@
@UnsupportedAppUsage
public int getInputMethodWindowVisibleHeight() {
try {
- return mService.getInputMethodWindowVisibleHeight();
+ final Completable.Int value = Completable.createInt();
+ mService.getInputMethodWindowVisibleHeight(ResultCallbacks.of(value));
+ return Completable.getIntResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3214,7 +3235,9 @@
public InputMethodSubtype getLastInputMethodSubtype() {
try {
- return mService.getLastInputMethodSubtype();
+ final Completable.InputMethodSubtype value = Completable.createInputMethodSubtype();
+ mService.getLastInputMethodSubtype(ResultCallbacks.of(value));
+ return Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/view/textservice/SuggestionsInfo.java b/core/java/android/view/textservice/SuggestionsInfo.java
index ca529f6..1301c49 100644
--- a/core/java/android/view/textservice/SuggestionsInfo.java
+++ b/core/java/android/view/textservice/SuggestionsInfo.java
@@ -53,6 +53,16 @@
*/
public static final int RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR = 0x0008;
+ /**
+ * Flag of the attributes of the suggestions that can be obtained by
+ * {@link #getSuggestionsAttributes}: this tells that the text service has an alternative way to
+ * show UI for the list of correction suggestions to the user. When this flag is set, the
+ * receiver of the result suggestions should mark the erroneous part of the text with a text
+ * signifier (for example, underline), but should not show any UI for the list of correction
+ * suggestions to the user (for example, in a popup window).
+ */
+ public static final int RESULT_ATTR_DONT_SHOW_UI_FOR_SUGGESTIONS = 0x0010;
+
private final int mSuggestionsAttributes;
private final String[] mSuggestions;
private final boolean mSuggestionsAvailable;
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 0788635..b06fa1a 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -477,6 +477,8 @@
mTextView.postDelayed(mSpellRunnable, SPELL_PAUSE_DURATION);
}
+ // When calling this method, RESULT_ATTR_LOOKS_LIKE_TYPO or RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR
+ // (or both) should be set in suggestionsInfo.
private void createMisspelledSuggestionSpan(Editable editable, SuggestionsInfo suggestionsInfo,
SpellCheckSpan spellCheckSpan, int offset, int length) {
final int spellCheckSpanStart = editable.getSpanStart(spellCheckSpan);
@@ -506,7 +508,10 @@
}
final int suggestionsAttrs = suggestionsInfo.getSuggestionsAttributes();
- int flags = SuggestionSpan.FLAG_EASY_CORRECT;
+ int flags = 0;
+ if ((suggestionsAttrs & SuggestionsInfo.RESULT_ATTR_DONT_SHOW_UI_FOR_SUGGESTIONS) == 0) {
+ flags |= SuggestionSpan.FLAG_EASY_CORRECT;
+ }
if ((suggestionsAttrs & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) != 0) {
flags |= SuggestionSpan.FLAG_MISSPELLED;
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 12c91fa..977a0e8 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -17,6 +17,7 @@
package android.widget;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.ContentInfo.FLAG_CONVERT_TO_PLAIN_TEXT;
import static android.view.ContentInfo.SOURCE_AUTOFILL;
import static android.view.ContentInfo.SOURCE_CLIPBOARD;
@@ -8738,6 +8739,9 @@
outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_ENTER_ACTION;
}
}
+ if (getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT) {
+ outAttrs.internalImeOptions |= EditorInfo.IME_FLAG_APP_WINDOW_PORTRAIT;
+ }
if (isMultilineInputType(outAttrs.inputType)) {
// Multi-line text editors should always show an enter key.
outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_ENTER_ACTION;
diff --git a/core/java/android/window/DisplayAreaOrganizer.java b/core/java/android/window/DisplayAreaOrganizer.java
index 8a1d4a0..1254647 100644
--- a/core/java/android/window/DisplayAreaOrganizer.java
+++ b/core/java/android/window/DisplayAreaOrganizer.java
@@ -164,15 +164,19 @@
}
/**
- * Creates a persistent task display area. It will be added to be the top most task display area
- * in the root.
+ * Creates a persistent {@link com.android.server.wm.TaskDisplayArea}.
*
* The new created TDA is organized by the organizer, and will be deleted on calling
* {@link #deleteTaskDisplayArea(WindowContainerToken)} or {@link #unregisterOrganizer()}.
*
- * @param displayId the display to create the new task display area in.
- * @param rootFeatureId the root display area to create the new task display area in. Caller can
- * use {@link #FEATURE_ROOT} as the root of the logical display.
+ * @param displayId the display to create the new TDA in.
+ * @param parentFeatureId the parent to create the new TDA in. If it is a
+ * {@link com.android.server.wm.RootDisplayArea}, the new TDA will be
+ * placed as the topmost TDA. If it is another TDA, the new TDA will be
+ * placed as the topmost child.
+ * Caller can use {@link #FEATURE_ROOT} as the root of the logical
+ * display, or {@link #FEATURE_DEFAULT_TASK_CONTAINER} as the default
+ * TDA.
* @param name the name for the new task display area.
* @return the new created task display area.
* @throws IllegalArgumentException if failed to create a new task display area.
@@ -181,11 +185,11 @@
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
@CallSuper
@NonNull
- public DisplayAreaAppearedInfo createTaskDisplayArea(int displayId, int rootFeatureId,
+ public DisplayAreaAppearedInfo createTaskDisplayArea(int displayId, int parentFeatureId,
@NonNull String name) {
try {
return getController().createTaskDisplayArea(
- mInterface, displayId, rootFeatureId, name);
+ mInterface, displayId, parentFeatureId, name);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/window/IDisplayAreaOrganizerController.aidl b/core/java/android/window/IDisplayAreaOrganizerController.aidl
index 26fa434..6c097bb 100644
--- a/core/java/android/window/IDisplayAreaOrganizerController.aidl
+++ b/core/java/android/window/IDisplayAreaOrganizerController.aidl
@@ -40,21 +40,25 @@
void unregisterOrganizer(in IDisplayAreaOrganizer organizer);
/**
- * Creates a persistent task display area. It will be added to be the top most task display area
- * in the root.
+ * Creates a persistent {@link com.android.server.wm.TaskDisplayArea}.
*
* The new created TDA is organized by the organizer, and will be deleted on calling
* {@link #deleteTaskDisplayArea(WindowContainerToken)} or {@link #unregisterOrganizer()}.
*
- * @param displayId the display to create the new task display area in.
- * @param rootFeatureId the root display area to create the new task display area in. Caller can
- * use {@link #FEATURE_ROOT} as the root of the logical display.
+ * @param displayId the display to create the new TDA in.
+ * @param parentFeatureId the parent to create the new TDA in. If it is a
+ * {@link com.android.server.wm.RootDisplayArea}, the new TDA will be
+ * placed as the topmost TDA. If it is another TDA, the new TDA will be
+ * placed as the topmost child.
+ * Caller can use {@link #FEATURE_ROOT} as the root of the logical
+ * display, or {@link #FEATURE_DEFAULT_TASK_CONTAINER} as the default
+ * TDA.
* @param name the name for the new task display area.
* @return the new created task display area.
* @throws IllegalArgumentException if failed to create a new task display area.
*/
DisplayAreaAppearedInfo createTaskDisplayArea(in IDisplayAreaOrganizer organizer, int displayId,
- int rootFeatureId, in String name);
+ int parentFeatureId, in String name);
/**
* Deletes a persistent task display area. It can only be one that created by an organizer.
diff --git a/core/java/android/window/ITaskOrganizer.aidl b/core/java/android/window/ITaskOrganizer.aidl
index b503184..88b2257 100644
--- a/core/java/android/window/ITaskOrganizer.aidl
+++ b/core/java/android/window/ITaskOrganizer.aidl
@@ -18,6 +18,7 @@
import android.view.SurfaceControl;
import android.app.ActivityManager;
+import android.window.StartingWindowInfo;
import android.window.WindowContainerToken;
/**
@@ -30,15 +31,15 @@
* application is starting. The client is responsible to add/remove the starting window if it
* has create a starting window for the Task.
*
- * @param taskInfo The information about the Task that's available
+ * @param info The information about the Task that's available
* @param appToken Token of the application being started.
*/
- void addStartingWindow(in ActivityManager.RunningTaskInfo taskInfo, IBinder appToken);
+ void addStartingWindow(in StartingWindowInfo info, IBinder appToken);
/**
* Called when the Task want to remove the starting window.
*/
- void removeStartingWindow(in ActivityManager.RunningTaskInfo taskInfo);
+ void removeStartingWindow(int taskId);
/**
* A callback when the Task is available for the registered organizer. The client is responsible
diff --git a/core/java/android/window/StartingWindowInfo.aidl b/core/java/android/window/StartingWindowInfo.aidl
new file mode 100644
index 0000000..69b18f0
--- /dev/null
+++ b/core/java/android/window/StartingWindowInfo.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+/** @hide */
+parcelable StartingWindowInfo;
\ No newline at end of file
diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java
new file mode 100644
index 0000000..2282cc5
--- /dev/null
+++ b/core/java/android/window/StartingWindowInfo.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.TestApi;
+import android.app.ActivityManager;
+import android.app.TaskInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.InsetsState;
+import android.view.WindowManager;
+
+/**
+ * Information you can retrieve about a starting window of a particular task that is currently
+ * start in the system.
+ * @hide
+ */
+@TestApi
+public final class StartingWindowInfo implements Parcelable {
+ /**
+ * The {@link TaskInfo} from this task.
+ * @hide
+ */
+ @NonNull
+ public ActivityManager.RunningTaskInfo taskInfo;
+
+ /**
+ * InsetsState of TopFullscreenOpaqueWindow
+ * @hide
+ */
+ @Nullable
+ public InsetsState topOpaqueWindowInsetsState;
+
+ /**
+ * LayoutParams of TopFullscreenOpaqueWindow
+ * @hide
+ */
+ @Nullable
+ public WindowManager.LayoutParams topOpaqueWindowLayoutParams;
+
+ /**
+ * LayoutParams of MainWindow
+ * @hide
+ */
+ @Nullable
+ public WindowManager.LayoutParams mainWindowLayoutParams;
+
+ /**
+ * @hide
+ */
+ @IntDef(flag = true, prefix = "TYPE_PARAMETER_", value = {
+ TYPE_PARAMETER_NEW_TASK,
+ TYPE_PARAMETER_TASK_SWITCH,
+ TYPE_PARAMETER_PROCESS_RUNNING,
+ TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT,
+ TYPE_PARAMETER_ACTIVITY_CREATED
+ })
+ public @interface StartingTypeParams {}
+
+ /**
+ * The parameters of the starting window...
+ * @hide
+ */
+ public static final int TYPE_PARAMETER_NEW_TASK = 0x00000001;
+ /** @hide */
+ public static final int TYPE_PARAMETER_TASK_SWITCH = 0x00000002;
+ /** @hide */
+ public static final int TYPE_PARAMETER_PROCESS_RUNNING = 0x00000004;
+ /** @hide */
+ public static final int TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT = 0x00000008;
+ /** @hide */
+ public static final int TYPE_PARAMETER_ACTIVITY_CREATED = 0x00000010;
+
+ /**
+ * The parameters which effect the starting window type.
+ * @see android.window.StartingWindowInfo.StartingTypeParams
+ * @hide
+ */
+ public int startingWindowTypeParameter;
+
+ public StartingWindowInfo() {
+
+ }
+
+ private StartingWindowInfo(@NonNull Parcel source) {
+ readFromParcel(source);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeTypedObject(taskInfo, flags);
+ dest.writeInt(startingWindowTypeParameter);
+ dest.writeTypedObject(topOpaqueWindowInsetsState, flags);
+ dest.writeTypedObject(topOpaqueWindowLayoutParams, flags);
+ dest.writeTypedObject(mainWindowLayoutParams, flags);
+ }
+
+ void readFromParcel(@NonNull Parcel source) {
+ taskInfo = source.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
+ startingWindowTypeParameter = source.readInt();
+ topOpaqueWindowInsetsState = source.readTypedObject(InsetsState.CREATOR);
+ topOpaqueWindowLayoutParams = source.readTypedObject(
+ WindowManager.LayoutParams.CREATOR);
+ mainWindowLayoutParams = source.readTypedObject(WindowManager.LayoutParams.CREATOR);
+ }
+
+ @Override
+ public String toString() {
+ return "StartingWindowInfo{taskId=" + taskInfo.taskId
+ + " displayId=" + taskInfo.displayId
+ + " topActivityType=" + taskInfo.topActivityType
+ + " preferredStartingWindowType="
+ + Integer.toHexString(startingWindowTypeParameter)
+ + " insetsState=" + topOpaqueWindowInsetsState
+ + " topWindowLayoutParams=" + topOpaqueWindowLayoutParams
+ + " mainWindowLayoutParams=" + mainWindowLayoutParams;
+ }
+
+ public static final @android.annotation.NonNull Creator<StartingWindowInfo> CREATOR =
+ new Creator<StartingWindowInfo>() {
+ public StartingWindowInfo createFromParcel(@NonNull Parcel source) {
+ return new StartingWindowInfo(source);
+ }
+ public StartingWindowInfo[] newArray(int size) {
+ return new StartingWindowInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index 12c4b5b..73b2fe1 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -89,19 +89,19 @@
* application is starting. The client is responsible to add/remove the starting window if it
* has create a starting window for the Task.
*
- * @param taskInfo The information about the Task that's available
+ * @param info The information about the Task that's available
* @param appToken Token of the application being started.
* context to for resources
*/
@BinderThread
- public void addStartingWindow(@NonNull ActivityManager.RunningTaskInfo taskInfo,
+ public void addStartingWindow(@NonNull StartingWindowInfo info,
@NonNull IBinder appToken) {}
/**
* Called when the Task want to remove the starting window.
*/
@BinderThread
- public void removeStartingWindow(@NonNull ActivityManager.RunningTaskInfo taskInfo) {}
+ public void removeStartingWindow(int taskId) {}
/**
* Called when a task with the registered windowing mode can be controlled by this task
@@ -221,13 +221,15 @@
private final ITaskOrganizer mInterface = new ITaskOrganizer.Stub() {
@Override
- public void addStartingWindow(ActivityManager.RunningTaskInfo taskInfo, IBinder appToken) {
- mExecutor.execute(() -> TaskOrganizer.this.addStartingWindow(taskInfo, appToken));
+
+ public void addStartingWindow(StartingWindowInfo windowInfo,
+ IBinder appToken) {
+ mExecutor.execute(() -> TaskOrganizer.this.addStartingWindow(windowInfo, appToken));
}
@Override
- public void removeStartingWindow(ActivityManager.RunningTaskInfo taskInfo) {
- mExecutor.execute(() -> TaskOrganizer.this.removeStartingWindow(taskInfo));
+ public void removeStartingWindow(int taskId) {
+ mExecutor.execute(() -> TaskOrganizer.this.removeStartingWindow(taskId));
}
@Override
diff --git a/core/java/com/android/internal/inputmethod/CallbackUtils.java b/core/java/com/android/internal/inputmethod/CallbackUtils.java
index a77583f..248feb8 100644
--- a/core/java/com/android/internal/inputmethod/CallbackUtils.java
+++ b/core/java/com/android/internal/inputmethod/CallbackUtils.java
@@ -19,10 +19,14 @@
import android.annotation.AnyThread;
import android.annotation.NonNull;
import android.os.RemoteException;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
import com.android.internal.view.InputBindResult;
+import java.util.List;
import java.util.function.BooleanSupplier;
+import java.util.function.IntSupplier;
import java.util.function.Supplier;
/**
@@ -67,7 +71,7 @@
/**
* A utility method using given {@link IBooleanResultCallback} to callback the result.
*
- * @param callback {@link IInputBindResultResultCallback} to be called back.
+ * @param callback {@link IBooleanResultCallback} to be called back.
* @param resultSupplier the supplier from which the result is provided.
*/
public static void onResult(@NonNull IBooleanResultCallback callback,
@@ -89,4 +93,111 @@
callback.onResult(result);
} catch (RemoteException ignored) { }
}
+
+ /**
+ * A utility method using given {@link IInputMethodSubtypeResultCallback} to callback the
+ * result.
+ *
+ * @param callback {@link IInputMethodSubtypeResultCallback} to be called back.
+ * @param resultSupplier the supplier from which the result is provided.
+ */
+ public static void onResult(@NonNull IInputMethodSubtypeResultCallback callback,
+ @NonNull Supplier<InputMethodSubtype> resultSupplier) {
+ InputMethodSubtype result = null;
+ Throwable exception = null;
+
+ try {
+ result = resultSupplier.get();
+ } catch (Throwable throwable) {
+ exception = throwable;
+ }
+
+ try {
+ if (exception != null) {
+ callback.onError(ThrowableHolder.of(exception));
+ return;
+ }
+ callback.onResult(result);
+ } catch (RemoteException ignored) { }
+ }
+
+ /**
+ * A utility method using given {@link IInputMethodSubtypeListResultCallback} to callback the
+ * result.
+ *
+ * @param callback {@link IInputMethodSubtypeListResultCallback} to be called back.
+ * @param resultSupplier the supplier from which the result is provided.
+ */
+ public static void onResult(@NonNull IInputMethodSubtypeListResultCallback callback,
+ @NonNull Supplier<List<InputMethodSubtype>> resultSupplier) {
+ List<InputMethodSubtype> result = null;
+ Throwable exception = null;
+
+ try {
+ result = resultSupplier.get();
+ } catch (Throwable throwable) {
+ exception = throwable;
+ }
+
+ try {
+ if (exception != null) {
+ callback.onError(ThrowableHolder.of(exception));
+ return;
+ }
+ callback.onResult(result);
+ } catch (RemoteException ignored) { }
+ }
+
+ /**
+ * A utility method using given {@link IInputMethodInfoListResultCallback} to callback the
+ * result.
+ *
+ * @param callback {@link IInputMethodInfoListResultCallback} to be called back.
+ * @param resultSupplier the supplier from which the result is provided.
+ */
+ public static void onResult(@NonNull IInputMethodInfoListResultCallback callback,
+ @NonNull Supplier<List<InputMethodInfo>> resultSupplier) {
+ List<InputMethodInfo> result = null;
+ Throwable exception = null;
+
+ try {
+ result = resultSupplier.get();
+ } catch (Throwable throwable) {
+ exception = throwable;
+ }
+
+ try {
+ if (exception != null) {
+ callback.onError(ThrowableHolder.of(exception));
+ return;
+ }
+ callback.onResult(result);
+ } catch (RemoteException ignored) { }
+ }
+
+ /**
+ * A utility method using given {@link IIntResultCallback} to callback the result.
+ *
+ * @param callback {@link IIntResultCallback} to be called back.
+ * @param resultSupplier the supplier from which the result is provided.
+ */
+ public static void onResult(@NonNull IIntResultCallback callback,
+ @NonNull IntSupplier resultSupplier) {
+ int result = 0;
+ Throwable exception = null;
+
+ try {
+ result = resultSupplier.getAsInt();
+ } catch (Throwable throwable) {
+ exception = throwable;
+ }
+
+ try {
+ if (exception != null) {
+ callback.onError(ThrowableHolder.of(exception));
+ return;
+ }
+ callback.onResult(result);
+ } catch (RemoteException ignored) { }
+ }
}
diff --git a/core/java/com/android/internal/inputmethod/Completable.java b/core/java/com/android/internal/inputmethod/Completable.java
index bd8c23e..1913fcd 100644
--- a/core/java/com/android/internal/inputmethod/Completable.java
+++ b/core/java/com/android/internal/inputmethod/Completable.java
@@ -23,10 +23,12 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.Log;
+import android.view.inputmethod.InputMethodSubtype;
import com.android.internal.annotations.GuardedBy;
import java.lang.annotation.Retention;
+import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -373,6 +375,27 @@
}
/**
+ * @return an instance of {@link Completable.InputMethodSubtype}.
+ */
+ public static Completable.InputMethodSubtype createInputMethodSubtype() {
+ return new Completable.InputMethodSubtype();
+ }
+
+ /**
+ * @return an instance of {@link Completable.InputMethodSubtypeList}.
+ */
+ public static Completable.InputMethodSubtypeList createInputMethodSubtypeList() {
+ return new Completable.InputMethodSubtypeList();
+ }
+
+ /**
+ * @return an instance of {@link Completable.InputMethodInfoList}.
+ */
+ public static Completable.InputMethodInfoList createInputMethodInfoList() {
+ return new Completable.InputMethodInfoList();
+ }
+
+ /**
* Completable object of {@link java.lang.Boolean}.
*/
public static final class Boolean extends Values<java.lang.Boolean> { }
@@ -401,6 +424,24 @@
extends Values<com.android.internal.view.InputBindResult> { }
/**
+ * Completable object of {@link android.view.inputmethod.InputMethodSubtype}.
+ */
+ public static final class InputMethodSubtype
+ extends Values<android.view.inputmethod.InputMethodSubtype> { }
+
+ /**
+ * Completable object of {@link List<android.view.inputmethod.InputMethodSubtype>}.
+ */
+ public static final class InputMethodSubtypeList
+ extends Values<List<android.view.inputmethod.InputMethodSubtype>> { }
+
+ /**
+ * Completable object of {@link List<android.view.inputmethod.InputMethodInfo>}.
+ */
+ public static final class InputMethodInfoList
+ extends Values<List<android.view.inputmethod.InputMethodInfo>> { }
+
+ /**
* Await the result by the {@link Completable.Values}.
*
* @return the result once {@link ValueBase#onComplete()}
@@ -413,6 +454,17 @@
}
/**
+ * Await the int result by the {@link Completable.Int}.
+ *
+ * @return the result once {@link ValueBase#onComplete()}
+ */
+ @AnyThread
+ public static int getIntResult(@NonNull Completable.Int value) {
+ value.await();
+ return value.getValue();
+ }
+
+ /**
* Await the result by the {@link Completable.Int}, and log it if there is no result after
* given timeout.
*
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodInfoListResultCallback.aidl b/core/java/com/android/internal/inputmethod/IInputMethodInfoListResultCallback.aidl
new file mode 100644
index 0000000..0dfd5da
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/IInputMethodInfoListResultCallback.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.inputmethod;
+
+import android.view.inputmethod.InputMethodInfo;
+import com.android.internal.inputmethod.ThrowableHolder;
+
+oneway interface IInputMethodInfoListResultCallback {
+ void onResult(in List<InputMethodInfo> result);
+ void onError(in ThrowableHolder exception);
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodSubtypeListResultCallback.aidl b/core/java/com/android/internal/inputmethod/IInputMethodSubtypeListResultCallback.aidl
new file mode 100644
index 0000000..619c87e
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/IInputMethodSubtypeListResultCallback.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.inputmethod;
+
+import android.view.inputmethod.InputMethodSubtype;
+import com.android.internal.inputmethod.ThrowableHolder;
+
+oneway interface IInputMethodSubtypeListResultCallback {
+ void onResult(in List<InputMethodSubtype> result);
+ void onError(in ThrowableHolder exception);
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodSubtypeResultCallback.aidl b/core/java/com/android/internal/inputmethod/IInputMethodSubtypeResultCallback.aidl
new file mode 100644
index 0000000..66c0902
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/IInputMethodSubtypeResultCallback.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.inputmethod;
+
+import android.view.inputmethod.InputMethodSubtype;
+import com.android.internal.inputmethod.ThrowableHolder;
+
+oneway interface IInputMethodSubtypeResultCallback {
+ void onResult(in InputMethodSubtype result);
+ void onError(in ThrowableHolder exception);
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/IIntResultCallback.aidl b/core/java/com/android/internal/inputmethod/IIntResultCallback.aidl
index bc5ed0d..ceda66c 100644
--- a/core/java/com/android/internal/inputmethod/IIntResultCallback.aidl
+++ b/core/java/com/android/internal/inputmethod/IIntResultCallback.aidl
@@ -16,6 +16,9 @@
package com.android.internal.inputmethod;
+import com.android.internal.inputmethod.ThrowableHolder;
+
oneway interface IIntResultCallback {
void onResult(int result);
+ void onError(in ThrowableHolder exception);
}
diff --git a/core/java/com/android/internal/inputmethod/ResultCallbacks.java b/core/java/com/android/internal/inputmethod/ResultCallbacks.java
index b07c5f8..6ce851b 100644
--- a/core/java/com/android/internal/inputmethod/ResultCallbacks.java
+++ b/core/java/com/android/internal/inputmethod/ResultCallbacks.java
@@ -20,10 +20,13 @@
import android.annotation.BinderThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
import com.android.internal.view.InputBindResult;
import java.lang.ref.WeakReference;
+import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -73,6 +76,16 @@
}
value.onComplete(result);
}
+
+ @BinderThread
+ @Override
+ public void onError(ThrowableHolder throwableHolder) {
+ final Completable.Int value = unwrap(atomicRef);
+ if (value == null) {
+ return;
+ }
+ value.onError(throwableHolder);
+ }
};
}
@@ -228,4 +241,115 @@
}
};
}
+
+ /**
+ * Creates {@link IInputMethodSubtypeResultCallback.Stub} that is to set
+ * {@link Completable.InputMethodSubtype} when receiving the result.
+ *
+ * @param value {@link Completable.InputMethodSubtype} to be set when receiving the result.
+ * @return {@link IInputMethodSubtypeResultCallback.Stub} that can be passed as a binder
+ * IPC parameter.
+ */
+ @AnyThread
+ public static IInputMethodSubtypeResultCallback.Stub of(
+ @NonNull Completable.InputMethodSubtype value) {
+ final AtomicReference<WeakReference<Completable.InputMethodSubtype>>
+ atomicRef = new AtomicReference<>(new WeakReference<>(value));
+
+ return new IInputMethodSubtypeResultCallback.Stub() {
+ @BinderThread
+ @Override
+ public void onResult(InputMethodSubtype result) {
+ final Completable.InputMethodSubtype value = unwrap(atomicRef);
+ if (value == null) {
+ return;
+ }
+ value.onComplete(result);
+ }
+
+ @BinderThread
+ @Override
+ public void onError(ThrowableHolder throwableHolder) {
+ final Completable.InputMethodSubtype value = unwrap(atomicRef);
+ if (value == null) {
+ return;
+ }
+ value.onError(throwableHolder);
+ }
+ };
+ }
+
+ /**
+ * Creates {@link IInputMethodSubtypeListResultCallback.Stub} that is to set
+ * {@link Completable.InputMethodSubtypeList} when receiving the result.
+ *
+ * @param value {@link Completable.InputMethodSubtypeList} to be set when receiving the result.
+ * @return {@link IInputMethodSubtypeListResultCallback.Stub} that can be passed as a binder
+ * IPC parameter.
+ */
+ @AnyThread
+ public static IInputMethodSubtypeListResultCallback.Stub of(
+ @NonNull Completable.InputMethodSubtypeList value) {
+ final AtomicReference<WeakReference<Completable.InputMethodSubtypeList>>
+ atomicRef = new AtomicReference<>(new WeakReference<>(value));
+
+ return new IInputMethodSubtypeListResultCallback.Stub() {
+ @BinderThread
+ @Override
+ public void onResult(List<InputMethodSubtype> result) {
+ final Completable.InputMethodSubtypeList value = unwrap(atomicRef);
+ if (value == null) {
+ return;
+ }
+ value.onComplete(result);
+ }
+
+ @BinderThread
+ @Override
+ public void onError(ThrowableHolder throwableHolder) {
+ final Completable.InputMethodSubtypeList value = unwrap(atomicRef);
+ if (value == null) {
+ return;
+ }
+ value.onError(throwableHolder);
+ }
+ };
+ }
+
+ /**
+ * Creates {@link IInputMethodInfoListResultCallback.Stub} that is to set
+ * {@link Completable.InputMethodInfoList} when receiving the result.
+ *
+ * @param value {@link Completable.InputMethodInfoList} to be set when receiving the result.
+ * @return {@link IInputMethodInfoListResultCallback.Stub} that can be passed as a binder
+ * IPC parameter.
+ */
+ @AnyThread
+ public static IInputMethodInfoListResultCallback.Stub of(
+ @NonNull Completable.InputMethodInfoList value) {
+ final AtomicReference<WeakReference<Completable.InputMethodInfoList>>
+ atomicRef = new AtomicReference<>(new WeakReference<>(value));
+
+ return new IInputMethodInfoListResultCallback.Stub() {
+ @BinderThread
+ @Override
+ public void onResult(List<InputMethodInfo> result) {
+ final Completable.InputMethodInfoList value = unwrap(atomicRef);
+ if (value == null) {
+ return;
+ }
+ value.onComplete(result);
+ }
+
+ @BinderThread
+ @Override
+ public void onError(ThrowableHolder throwableHolder) {
+ final Completable.InputMethodInfoList value = unwrap(atomicRef);
+ if (value == null) {
+ return;
+ }
+ value.onError(throwableHolder);
+ }
+ };
+ }
}
diff --git a/core/java/com/android/internal/net/NetworkUtilsInternal.java b/core/java/com/android/internal/net/NetworkUtilsInternal.java
new file mode 100644
index 0000000..571d7e7
--- /dev/null
+++ b/core/java/com/android/internal/net/NetworkUtilsInternal.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.net;
+
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+
+import android.annotation.NonNull;
+import android.system.Os;
+
+/** @hide */
+public class NetworkUtilsInternal {
+
+ private static final int[] ADDRESS_FAMILIES = new int[] {AF_INET, AF_INET6};
+
+ /**
+ * Allow/Disallow creating AF_INET/AF_INET6 sockets and DNS lookups for current process.
+ *
+ * @param allowNetworking whether to allow or disallow creating AF_INET/AF_INET6 sockets
+ * and DNS lookups.
+ */
+ public static native void setAllowNetworkingForProcess(boolean allowNetworking);
+
+ /**
+ * Returns true if the hostname is weakly validated.
+ * @param hostname Name of host to validate.
+ * @return True if it's a valid-ish hostname.
+ *
+ * @hide
+ */
+ public static boolean isWeaklyValidatedHostname(@NonNull String hostname) {
+ // TODO(b/34953048): Use a validation method that permits more accurate,
+ // but still inexpensive, checking of likely valid DNS hostnames.
+ final String weakHostnameRegex = "^[a-zA-Z0-9_.-]+$";
+ if (!hostname.matches(weakHostnameRegex)) {
+ return false;
+ }
+
+ for (int address_family : ADDRESS_FAMILIES) {
+ if (Os.inet_pton(address_family, hostname) != null) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Safely multiple a value by a rational.
+ * <p>
+ * Internally it uses integer-based math whenever possible, but switches
+ * over to double-based math if values would overflow.
+ * @hide
+ */
+ public static long multiplySafeByRational(long value, long num, long den) {
+ if (den == 0) {
+ throw new ArithmeticException("Invalid Denominator");
+ }
+ long x = value;
+ long y = num;
+
+ // Logic shamelessly borrowed from Math.multiplyExact()
+ long r = x * y;
+ long ax = Math.abs(x);
+ long ay = Math.abs(y);
+ if (((ax | ay) >>> 31 != 0)) {
+ // Some bits greater than 2^31 that might cause overflow
+ // Check the result using the divide operator
+ // and check for the special case of Long.MIN_VALUE * -1
+ if (((y != 0) && (r / y != x))
+ || (x == Long.MIN_VALUE && y == -1)) {
+ // Use double math to avoid overflowing
+ return (long) (((double) num / den) * value);
+ }
+ }
+ return r / den;
+ }
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 5aedd1e..0fa0df6 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -953,7 +953,8 @@
/**
* The Bluetooth controller activity (time in tx, rx, idle, and power consumed) for the device.
*/
- ControllerActivityCounterImpl mBluetoothActivity;
+ @VisibleForTesting
+ protected ControllerActivityCounterImpl mBluetoothActivity;
/**
* The Modem controller activity (time in tx, rx, idle, and power consumed) for the device.
@@ -1106,6 +1107,16 @@
private long[] mCpuFreqs;
/**
+ * Times spent by the system server process grouped by cluster and CPU speed.
+ */
+ private LongSamplingCounterArray mSystemServerCpuTimesUs;
+
+ /**
+ * Times spent by the system server threads grouped by cluster and CPU speed.
+ */
+ private LongSamplingCounterArray mSystemServerThreadCpuTimesUs;
+
+ /**
* Times spent by the system server threads handling incoming binder requests.
*/
private LongSamplingCounterArray mBinderThreadCpuTimesUs;
@@ -10844,14 +10855,6 @@
}
}
- /**
- * Starts tracking CPU time-in-state for threads of the system server process,
- * keeping a separate account of threads receiving incoming binder calls.
- */
- public void startTrackingSystemServerCpuTime() {
- mSystemServerCpuThreadReader.startTrackingThreadCpuTime();
- }
-
public void setCallback(BatteryCallback cb) {
mCallback = cb;
}
@@ -11504,6 +11507,8 @@
MeasuredEnergyStats.resetIfNotNull(mGlobalMeasuredEnergyStats);
+ resetIfNotNull(mSystemServerCpuTimesUs, false, elapsedRealtimeUs);
+ resetIfNotNull(mSystemServerThreadCpuTimesUs, false, elapsedRealtimeUs);
resetIfNotNull(mBinderThreadCpuTimesUs, false, elapsedRealtimeUs);
mLastHistoryStepDetails = null;
@@ -12703,17 +12708,27 @@
return;
}
- if (mBinderThreadCpuTimesUs == null) {
+ if (mSystemServerCpuTimesUs == null) {
+ mSystemServerCpuTimesUs = new LongSamplingCounterArray(mOnBatteryTimeBase);
+ mSystemServerThreadCpuTimesUs = new LongSamplingCounterArray(mOnBatteryTimeBase);
mBinderThreadCpuTimesUs = new LongSamplingCounterArray(mOnBatteryTimeBase);
}
+ mSystemServerCpuTimesUs.addCountLocked(systemServiceCpuThreadTimes.processCpuTimesUs);
+ mSystemServerThreadCpuTimesUs.addCountLocked(systemServiceCpuThreadTimes.threadCpuTimesUs);
mBinderThreadCpuTimesUs.addCountLocked(systemServiceCpuThreadTimes.binderThreadCpuTimesUs);
if (DEBUG_BINDER_STATS) {
- Slog.d(TAG, "System server threads per CPU cluster (incoming binder threads)");
+ Slog.d(TAG, "System server threads per CPU cluster (binder threads/total threads/%)");
+ long totalCpuTimeMs = 0;
+ long totalThreadTimeMs = 0;
long binderThreadTimeMs = 0;
int cpuIndex = 0;
- final long[] binderThreadCpuTimesUs = mBinderThreadCpuTimesUs.getCountsLocked(
- BatteryStats.STATS_SINCE_CHARGED);
+ final long[] systemServerCpuTimesUs =
+ mSystemServerCpuTimesUs.getCountsLocked(0);
+ final long[] systemServerThreadCpuTimesUs =
+ mSystemServerThreadCpuTimesUs.getCountsLocked(0);
+ final long[] binderThreadCpuTimesUs =
+ mBinderThreadCpuTimesUs.getCountsLocked(0);
int index = 0;
int numCpuClusters = mPowerProfile.getNumCpuClusters();
for (int cluster = 0; cluster < numCpuClusters; cluster++) {
@@ -12724,15 +12739,28 @@
if (speed != 0) {
sb.append(", ");
}
+ long totalCountMs = systemServerThreadCpuTimesUs[index] / 1000;
long binderCountMs = binderThreadCpuTimesUs[index] / 1000;
- sb.append(TextUtils.formatSimple("%10d", binderCountMs));
+ sb.append(String.format("%d/%d(%.1f%%)",
+ binderCountMs,
+ totalCountMs,
+ totalCountMs != 0 ? (double) binderCountMs * 100 / totalCountMs : 0));
+ totalCpuTimeMs += systemServerCpuTimesUs[index] / 1000;
+ totalThreadTimeMs += totalCountMs;
binderThreadTimeMs += binderCountMs;
index++;
}
cpuIndex += mPowerProfile.getNumCoresInCpuCluster(cluster);
Slog.d(TAG, sb.toString());
}
+
+ Slog.d(TAG, "Total system server CPU time (ms): " + totalCpuTimeMs);
+ Slog.d(TAG, "Total system server thread time (ms): " + totalThreadTimeMs);
+ Slog.d(TAG, String.format("Total Binder thread time (ms): %d (%.1f%%)",
+ binderThreadTimeMs,
+ binderThreadTimeMs != 0
+ ? (double) binderThreadTimeMs * 100 / totalThreadTimeMs : 0));
}
}
@@ -14007,16 +14035,60 @@
}
- /**
- * Estimates the time spent by the system server handling incoming binder requests.
- */
@Override
public long[] getSystemServiceTimeAtCpuSpeeds() {
- if (mBinderThreadCpuTimesUs == null) {
+ // Estimates the time spent by the system server handling incoming binder requests.
+ //
+ // The data that we can get from the kernel is this:
+ // - CPU duration for a (thread - cluster - CPU speed) combination
+ // - CPU duration for a (UID - cluster - CPU speed) combination
+ //
+ // The configuration we have in the Power Profile is this:
+ // - Average CPU power for a (cluster - CPU speed) combination.
+ //
+ // The model used by BatteryStats can be illustrated with this example:
+ //
+ // - Let's say the system server has 10 threads.
+ // - These 10 threads spent 1000 ms of CPU time in aggregate
+ // - Of the 10 threads 4 were execute exclusively incoming binder calls.
+ // - These 4 "binder" threads consumed 600 ms of CPU time in aggregate
+ // - The real time spent by the system server process doing all of this is, say, 200 ms.
+ //
+ // We will assume that power consumption is proportional to the time spent by the CPU
+ // across all threads. This is a crude assumption, but we don't have more detailed data.
+ // Thus,
+ // binderRealTime = realTime * aggregateBinderThreadTime / aggregateAllThreadTime
+ //
+ // In our example,
+ // binderRealTime = 200 * 600 / 1000 = 120ms
+ //
+ // We can then multiply this estimated time by the average power to obtain an estimate
+ // of the total power consumed by incoming binder calls for the given cluster/speed
+ // combination.
+
+ if (mSystemServerCpuTimesUs == null) {
return null;
}
- return mBinderThreadCpuTimesUs.getCountsLocked(BatteryStats.STATS_SINCE_CHARGED);
+ final long[] systemServerCpuTimesUs = mSystemServerCpuTimesUs.getCountsLocked(
+ BatteryStats.STATS_SINCE_CHARGED);
+ final long [] systemServerThreadCpuTimesUs = mSystemServerThreadCpuTimesUs.getCountsLocked(
+ BatteryStats.STATS_SINCE_CHARGED);
+ final long[] binderThreadCpuTimesUs = mBinderThreadCpuTimesUs.getCountsLocked(
+ BatteryStats.STATS_SINCE_CHARGED);
+
+ final int size = systemServerCpuTimesUs.length;
+ final long[] results = new long[size];
+
+ for (int i = 0; i < size; i++) {
+ if (systemServerThreadCpuTimesUs[i] == 0) {
+ continue;
+ }
+
+ results[i] = systemServerCpuTimesUs[i] * binderThreadCpuTimesUs[i]
+ / systemServerThreadCpuTimesUs[i];
+ }
+ return results;
}
/**
@@ -14412,7 +14484,7 @@
}
updateSystemServiceCallStats();
- if (mBinderThreadCpuTimesUs != null) {
+ if (mSystemServerThreadCpuTimesUs != null) {
pw.println("Per UID System server binder time in ms:");
long[] systemServiceTimeAtCpuSpeeds = getSystemServiceTimeAtCpuSpeeds();
for (int i = 0; i < size; i++) {
@@ -15999,6 +16071,9 @@
mUidStats.append(uid, u);
}
+ mSystemServerCpuTimesUs = LongSamplingCounterArray.readFromParcel(in, mOnBatteryTimeBase);
+ mSystemServerThreadCpuTimesUs = LongSamplingCounterArray.readFromParcel(in,
+ mOnBatteryTimeBase);
mBinderThreadCpuTimesUs = LongSamplingCounterArray.readFromParcel(in, mOnBatteryTimeBase);
}
@@ -16207,6 +16282,8 @@
} else {
out.writeInt(0);
}
+ LongSamplingCounterArray.writeToParcel(out, mSystemServerCpuTimesUs);
+ LongSamplingCounterArray.writeToParcel(out, mSystemServerThreadCpuTimesUs);
LongSamplingCounterArray.writeToParcel(out, mBinderThreadCpuTimesUs);
}
diff --git a/core/java/com/android/internal/os/BluetoothPowerCalculator.java b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
index 11099be..f5690e0 100644
--- a/core/java/com/android/internal/os/BluetoothPowerCalculator.java
+++ b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
@@ -15,8 +15,13 @@
*/
package com.android.internal.os;
+import android.os.BatteryConsumer;
import android.os.BatteryStats;
+import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
import android.os.Process;
+import android.os.SystemBatteryConsumer;
+import android.os.UidBatteryConsumer;
import android.os.UserHandle;
import android.util.Log;
import android.util.SparseArray;
@@ -30,8 +35,16 @@
private final double mRxMa;
private final double mTxMa;
private final boolean mHasBluetoothPowerController;
- private double mAppTotalPowerMah = 0;
- private long mAppTotalTimeMs = 0;
+
+ private static class PowerAndDuration {
+ public long durationMs;
+ public double powerMah;
+ }
+
+ // Objects used for passing calculation results. Fields are used to avoid allocations.
+ private final PowerAndDuration mUidPowerAndDuration = new PowerAndDuration();
+ private final PowerAndDuration mTotalPowerAndDuration = new PowerAndDuration();
+ private final PowerAndDuration mSystemPowerAndDuration = new PowerAndDuration();
public BluetoothPowerCalculator(PowerProfile profile) {
mIdleMa = profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE);
@@ -41,16 +54,90 @@
}
@Override
+ public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
+ long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
+ SparseArray<UserHandle> asUsers) {
+ if (!mHasBluetoothPowerController || !batteryStats.hasBluetoothActivityReporting()) {
+ return;
+ }
+
+ mTotalPowerAndDuration.durationMs = 0;
+ mTotalPowerAndDuration.powerMah = 0;
+
+ SystemBatteryConsumer.Builder systemBatteryConsumerBuilder =
+ builder.getOrCreateSystemBatteryConsumerBuilder(
+ SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH);
+
+ final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
+ builder.getUidBatteryConsumerBuilders();
+ for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
+ final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
+ calculateApp(app);
+ if (app.getUid() == Process.BLUETOOTH_UID) {
+ app.setSystemComponent(true);
+ systemBatteryConsumerBuilder.addUidBatteryConsumer(app);
+ }
+ }
+
+ final BatteryStats.ControllerActivityCounter counter =
+ batteryStats.getBluetoothControllerActivity();
+
+ calculatePowerAndDuration(counter, mSystemPowerAndDuration);
+
+ // Subtract what the apps used, but clamp to 0.
+ final long systemComponentDurationMs = Math.max(0,
+ mSystemPowerAndDuration.durationMs - mTotalPowerAndDuration.durationMs);
+ final double systemComponentPowerMah = Math.max(0,
+ mSystemPowerAndDuration.powerMah - mTotalPowerAndDuration.powerMah);
+
+ systemBatteryConsumerBuilder
+ .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_BLUETOOTH,
+ systemComponentDurationMs)
+ .setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
+ systemComponentPowerMah);
+ }
+
+ private void calculateApp(UidBatteryConsumer.Builder app) {
+ calculatePowerAndDuration(app.getBatteryStatsUid().getBluetoothControllerActivity(),
+ mUidPowerAndDuration);
+
+ app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_BLUETOOTH,
+ mUidPowerAndDuration.durationMs)
+ .setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
+ mUidPowerAndDuration.powerMah);
+
+ mTotalPowerAndDuration.powerMah += mUidPowerAndDuration.powerMah;
+ mTotalPowerAndDuration.durationMs += mUidPowerAndDuration.durationMs;
+ }
+
+ @Override
public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
if (!mHasBluetoothPowerController || !batteryStats.hasBluetoothActivityReporting()) {
return;
}
+ mTotalPowerAndDuration.durationMs = 0;
+ mTotalPowerAndDuration.powerMah = 0;
+
super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers);
BatterySipper bs = new BatterySipper(BatterySipper.DrainType.BLUETOOTH, null, 0);
- calculateRemaining(bs, batteryStats, rawRealtimeUs, rawUptimeUs, statsType);
+ calculatePowerAndDuration(batteryStats.getBluetoothControllerActivity(),
+ mSystemPowerAndDuration);
+
+ // Subtract what the apps used, but clamp to 0.
+ double powerMah =
+ Math.max(0, mSystemPowerAndDuration.powerMah - mTotalPowerAndDuration.powerMah);
+ final long durationMs =
+ Math.max(0, mSystemPowerAndDuration.durationMs - mTotalPowerAndDuration.durationMs);
+ if (DEBUG && powerMah != 0) {
+ Log.d(TAG, "Bluetooth active: time=" + (durationMs)
+ + " power=" + formatCharge(powerMah));
+ }
+
+ bs.bluetoothPowerMah = powerMah;
+ bs.bluetoothRunningTimeMs = durationMs;
for (int i = sippers.size() - 1; i >= 0; i--) {
BatterySipper app = sippers.get(i);
@@ -69,65 +156,42 @@
protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
long rawUptimeUs, int statsType) {
- final BatteryStats.ControllerActivityCounter counter = u.getBluetoothControllerActivity();
- if (counter == null) {
- return;
- }
+ calculatePowerAndDuration(u.getBluetoothControllerActivity(), mUidPowerAndDuration);
- final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(statsType);
- final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(statsType);
- final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(statsType);
- final long totalTimeMs = idleTimeMs + txTimeMs + rxTimeMs;
- double powerMah = counter.getPowerCounter().getCountLocked(statsType)
- / (double)(1000*60*60);
-
- if (powerMah == 0) {
- powerMah = ((idleTimeMs * mIdleMa) + (rxTimeMs * mRxMa) + (txTimeMs * mTxMa))
- / (1000*60*60);
- }
-
- app.bluetoothPowerMah = powerMah;
- app.bluetoothRunningTimeMs = totalTimeMs;
+ app.bluetoothPowerMah = mUidPowerAndDuration.powerMah;
+ app.bluetoothRunningTimeMs = mUidPowerAndDuration.durationMs;
app.btRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_BT_RX_DATA, statsType);
app.btTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_BT_TX_DATA, statsType);
- mAppTotalPowerMah += powerMah;
- mAppTotalTimeMs += totalTimeMs;
+ mTotalPowerAndDuration.powerMah += mUidPowerAndDuration.powerMah;
+ mTotalPowerAndDuration.durationMs += mUidPowerAndDuration.durationMs;
}
- private void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
- long rawUptimeUs, int statsType) {
- final BatteryStats.ControllerActivityCounter counter =
- stats.getBluetoothControllerActivity();
+ private void calculatePowerAndDuration(BatteryStats.ControllerActivityCounter counter,
+ PowerAndDuration powerAndDuration) {
+ if (counter == null) {
+ powerAndDuration.durationMs = 0;
+ powerAndDuration.powerMah = 0;
+ return;
+ }
- final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(statsType);
- final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(statsType);
- final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(statsType);
+ final long idleTimeMs =
+ counter.getIdleTimeCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
+ final long rxTimeMs =
+ counter.getRxTimeCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
+ final long txTimeMs =
+ counter.getTxTimeCounters()[0].getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
final long totalTimeMs = idleTimeMs + txTimeMs + rxTimeMs;
- double powerMah = counter.getPowerCounter().getCountLocked(statsType)
- / (double)(1000*60*60);
+ double powerMah =
+ counter.getPowerCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED)
+ / (double) (1000 * 60 * 60);
if (powerMah == 0) {
- // Some devices do not report the power, so calculate it.
powerMah = ((idleTimeMs * mIdleMa) + (rxTimeMs * mRxMa) + (txTimeMs * mTxMa))
- / (1000*60*60);
+ / (1000 * 60 * 60);
}
- // Subtract what the apps used, but clamp to 0.
- powerMah = Math.max(0, powerMah - mAppTotalPowerMah);
-
- if (DEBUG && powerMah != 0) {
- Log.d(TAG, "Bluetooth active: time=" + (totalTimeMs)
- + " power=" + formatCharge(powerMah));
- }
-
- app.bluetoothPowerMah = powerMah;
- app.bluetoothRunningTimeMs = Math.max(0, totalTimeMs - mAppTotalTimeMs);
- }
-
- @Override
- public void reset() {
- mAppTotalPowerMah = 0;
- mAppTotalTimeMs = 0;
+ powerAndDuration.durationMs = totalTimeMs;
+ powerAndDuration.powerMah = powerMah;
}
}
diff --git a/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java b/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java
index 4d2a08a..e6a9623 100644
--- a/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java
+++ b/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java
@@ -16,12 +16,23 @@
package com.android.internal.os;
+import static android.os.Process.PROC_OUT_LONG;
+import static android.os.Process.PROC_SPACE_TERM;
+
import android.annotation.Nullable;
+import android.os.Process;
+import android.system.Os;
+import android.system.OsConstants;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import java.io.IOException;
+import java.nio.file.DirectoryIteratorException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.Arrays;
/**
@@ -34,65 +45,93 @@
private static final String TAG = "KernelSingleProcCpuThreadRdr";
private static final boolean DEBUG = false;
+ private static final boolean NATIVE_ENABLED = true;
+
+ /**
+ * The name of the file to read CPU statistics from, must be found in {@code
+ * /proc/$PID/task/$TID}
+ */
+ private static final String CPU_STATISTICS_FILENAME = "time_in_state";
+
+ private static final String PROC_STAT_FILENAME = "stat";
+
+ /** Directory under /proc/$PID containing CPU stats files for threads */
+ public static final String THREAD_CPU_STATS_DIRECTORY = "task";
+
+ /** Default mount location of the {@code proc} filesystem */
+ private static final Path DEFAULT_PROC_PATH = Paths.get("/proc");
+
+ /** The initial {@code time_in_state} file for {@link ProcTimeInStateReader} */
+ private static final Path INITIAL_TIME_IN_STATE_PATH = Paths.get("self/time_in_state");
+
+ /** See https://man7.org/linux/man-pages/man5/proc.5.html */
+ private static final int[] PROCESS_FULL_STATS_FORMAT = new int[] {
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM | PROC_OUT_LONG, // 14: utime
+ PROC_SPACE_TERM | PROC_OUT_LONG, // 15: stime
+ // Ignore remaining fields
+ };
+
+ private final long[] mProcessFullStatsData = new long[2];
+
+ private static final int PROCESS_FULL_STAT_UTIME = 0;
+ private static final int PROCESS_FULL_STAT_STIME = 1;
+
+ /** Used to read and parse {@code time_in_state} files */
+ private final ProcTimeInStateReader mProcTimeInStateReader;
private final int mPid;
- private final CpuTimeInStateReader mCpuTimeInStateReader;
+ /** Where the proc filesystem is mounted */
+ private final Path mProcPath;
- private int[] mSelectedThreadNativeTids = new int[0]; // Sorted
+ // How long a CPU jiffy is in milliseconds.
+ private final long mJiffyMillis;
+
+ // Path: /proc/<pid>/stat
+ private final String mProcessStatFilePath;
+
+ // Path: /proc/<pid>/task
+ private final Path mThreadsDirectoryPath;
/**
- * Count of frequencies read from the {@code time_in_state} file.
+ * Count of frequencies read from the {@code time_in_state} file. Read from {@link
+ * #mProcTimeInStateReader#getCpuFrequenciesKhz()}.
*/
private int mFrequencyCount;
- private boolean mIsTracking;
-
- /**
- * A CPU time-in-state provider for testing. Imitates the behavior of the corresponding
- * methods in frameworks/native/libs/cputimeinstate/cputimeinstate.c
- */
- @VisibleForTesting
- public interface CpuTimeInStateReader {
- /**
- * Returns the overall number of cluster-frequency combinations.
- */
- int getCpuFrequencyCount();
-
- /**
- * Returns true to indicate success.
- *
- * Called from native.
- */
- boolean startTrackingProcessCpuTimes(int tgid);
-
- /**
- * Returns true to indicate success.
- *
- * Called from native.
- */
- boolean startAggregatingTaskCpuTimes(int pid, int aggregationKey);
-
- /**
- * Must return an array of strings formatted like this:
- * "aggKey:t0_0 t0_1...:t1_0 t1_1..."
- * Times should be provided in nanoseconds.
- *
- * Called from native.
- */
- String[] getAggregatedTaskCpuFreqTimes(int pid);
- }
-
/**
* Create with a path where `proc` is mounted. Used primarily for testing
*
* @param pid PID of the process whose threads are to be read.
+ * @param procPath where `proc` is mounted (to find, see {@code mount | grep ^proc})
*/
@VisibleForTesting
- public KernelSingleProcessCpuThreadReader(int pid,
- @Nullable CpuTimeInStateReader cpuTimeInStateReader) throws IOException {
+ public KernelSingleProcessCpuThreadReader(
+ int pid,
+ Path procPath) throws IOException {
mPid = pid;
- mCpuTimeInStateReader = cpuTimeInStateReader;
+ mProcPath = procPath;
+ mProcTimeInStateReader = new ProcTimeInStateReader(
+ mProcPath.resolve(INITIAL_TIME_IN_STATE_PATH));
+ long jiffyHz = Os.sysconf(OsConstants._SC_CLK_TCK);
+ mJiffyMillis = 1000 / jiffyHz;
+ mProcessStatFilePath =
+ mProcPath.resolve(String.valueOf(mPid)).resolve(PROC_STAT_FILENAME).toString();
+ mThreadsDirectoryPath =
+ mProcPath.resolve(String.valueOf(mPid)).resolve(THREAD_CPU_STATS_DIRECTORY);
}
/**
@@ -103,7 +142,7 @@
@Nullable
public static KernelSingleProcessCpuThreadReader create(int pid) {
try {
- return new KernelSingleProcessCpuThreadReader(pid, null);
+ return new KernelSingleProcessCpuThreadReader(pid, DEFAULT_PROC_PATH);
} catch (IOException e) {
Slog.e(TAG, "Failed to initialize KernelSingleProcessCpuThreadReader", e);
return null;
@@ -111,98 +150,146 @@
}
/**
- * Starts tracking aggregated CPU time-in-state of all threads of the process with the PID
- * supplied in the constructor.
- */
- public void startTrackingThreadCpuTimes() {
- if (!mIsTracking) {
- if (!startTrackingProcessCpuTimes(mPid, mCpuTimeInStateReader)) {
- Slog.e(TAG, "Failed to start tracking process CPU times for " + mPid);
- }
- if (mSelectedThreadNativeTids.length > 0) {
- if (!startAggregatingThreadCpuTimes(mSelectedThreadNativeTids,
- mCpuTimeInStateReader)) {
- Slog.e(TAG, "Failed to start tracking aggregated thread CPU times for "
- + Arrays.toString(mSelectedThreadNativeTids));
- }
- }
- mIsTracking = true;
- }
- }
-
- /**
- * @param nativeTids an array of native Thread IDs whose CPU times should
- * be aggregated as a group. This is expected to be a subset
- * of all thread IDs owned by the process.
- */
- public void setSelectedThreadIds(int[] nativeTids) {
- mSelectedThreadNativeTids = nativeTids.clone();
- if (mIsTracking) {
- startAggregatingThreadCpuTimes(mSelectedThreadNativeTids, mCpuTimeInStateReader);
- }
- }
-
- /**
- * Get the CPU frequencies that correspond to the times reported in {@link ProcessCpuUsage}.
+ * Get the CPU frequencies that correspond to the times reported in {@link
+ * ProcessCpuUsage#processCpuTimesMillis} etc.
*/
public int getCpuFrequencyCount() {
if (mFrequencyCount == 0) {
- mFrequencyCount = getCpuFrequencyCount(mCpuTimeInStateReader);
+ mFrequencyCount = mProcTimeInStateReader.getFrequenciesKhz().length;
}
return mFrequencyCount;
}
/**
- * Get the total CPU usage of the process with the PID specified in the
- * constructor. The CPU usage time is aggregated across all threads and may
- * exceed the time the entire process has been running.
+ * Get the total and per-thread CPU usage of the process with the PID specified in the
+ * constructor.
+ *
+ * @param selectedThreadIds a SORTED array of native Thread IDs whose CPU times should
+ * be aggregated as a group. This is expected to be a subset
+ * of all thread IDs owned by the process.
*/
@Nullable
- public ProcessCpuUsage getProcessCpuUsage() {
+ public ProcessCpuUsage getProcessCpuUsage(int[] selectedThreadIds) {
if (DEBUG) {
- Slog.d(TAG, "Reading CPU thread usages for PID " + mPid);
+ Slog.d(TAG, "Reading CPU thread usages with directory " + mProcPath + " process ID "
+ + mPid);
}
- ProcessCpuUsage processCpuUsage = new ProcessCpuUsage(getCpuFrequencyCount());
+ int cpuFrequencyCount = getCpuFrequencyCount();
+ ProcessCpuUsage processCpuUsage = new ProcessCpuUsage(cpuFrequencyCount);
- boolean result = readProcessCpuUsage(mPid,
- processCpuUsage.threadCpuTimesMillis,
- processCpuUsage.selectedThreadCpuTimesMillis,
- mCpuTimeInStateReader);
- if (!result) {
+ if (NATIVE_ENABLED) {
+ boolean result = readProcessCpuUsage(mProcPath.toString(), mPid,
+ selectedThreadIds, processCpuUsage.processCpuTimesMillis,
+ processCpuUsage.threadCpuTimesMillis,
+ processCpuUsage.selectedThreadCpuTimesMillis);
+ if (!result) {
+ return null;
+ }
+ return processCpuUsage;
+ }
+
+ if (!isSorted(selectedThreadIds)) {
+ throw new IllegalArgumentException("selectedThreadIds is not sorted: "
+ + Arrays.toString(selectedThreadIds));
+ }
+
+ if (!Process.readProcFile(mProcessStatFilePath, PROCESS_FULL_STATS_FORMAT, null,
+ mProcessFullStatsData, null)) {
+ Slog.e(TAG, "Failed to read process stat file " + mProcessStatFilePath);
return null;
}
- if (DEBUG) {
- Slog.d(TAG, "threadCpuTimesMillis = "
- + Arrays.toString(processCpuUsage.threadCpuTimesMillis));
- Slog.d(TAG, "selectedThreadCpuTimesMillis = "
- + Arrays.toString(processCpuUsage.selectedThreadCpuTimesMillis));
+ long utime = mProcessFullStatsData[PROCESS_FULL_STAT_UTIME];
+ long stime = mProcessFullStatsData[PROCESS_FULL_STAT_STIME];
+
+ long processCpuTimeMillis = (utime + stime) * mJiffyMillis;
+
+ try (DirectoryStream<Path> threadPaths = Files.newDirectoryStream(mThreadsDirectoryPath)) {
+ for (Path threadDirectory : threadPaths) {
+ readThreadCpuUsage(processCpuUsage, selectedThreadIds, threadDirectory);
+ }
+ } catch (IOException | DirectoryIteratorException e) {
+ // Expected when a process finishes
+ return null;
+ }
+
+ // Estimate per cluster per frequency CPU time for the entire process
+ // by distributing the total process CPU time proportionately to how much
+ // CPU time its threads took on those clusters/frequencies. This algorithm
+ // works more accurately when when we have equally distributed concurrency.
+ // TODO(b/169279846): obtain actual process CPU times from the kernel
+ long totalCpuTimeAllThreads = 0;
+ for (int i = cpuFrequencyCount - 1; i >= 0; i--) {
+ totalCpuTimeAllThreads += processCpuUsage.threadCpuTimesMillis[i];
+ }
+
+ for (int i = cpuFrequencyCount - 1; i >= 0; i--) {
+ processCpuUsage.processCpuTimesMillis[i] =
+ processCpuTimeMillis * processCpuUsage.threadCpuTimesMillis[i]
+ / totalCpuTimeAllThreads;
}
return processCpuUsage;
}
+ /**
+ * Reads a thread's CPU usage and aggregates the per-cluster per-frequency CPU times.
+ *
+ * @param threadDirectory the {@code /proc} directory of the thread
+ */
+ private void readThreadCpuUsage(ProcessCpuUsage processCpuUsage, int[] selectedThreadIds,
+ Path threadDirectory) {
+ // Get the thread ID from the directory name
+ final int threadId;
+ try {
+ final String directoryName = threadDirectory.getFileName().toString();
+ threadId = Integer.parseInt(directoryName);
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "Failed to parse thread ID when iterating over /proc/*/task", e);
+ return;
+ }
+
+ // Get the CPU statistics from the directory
+ final Path threadCpuStatPath = threadDirectory.resolve(CPU_STATISTICS_FILENAME);
+ final long[] cpuUsages = mProcTimeInStateReader.getUsageTimesMillis(threadCpuStatPath);
+ if (cpuUsages == null) {
+ return;
+ }
+
+ final int cpuFrequencyCount = getCpuFrequencyCount();
+ final boolean isSelectedThread = Arrays.binarySearch(selectedThreadIds, threadId) >= 0;
+ for (int i = cpuFrequencyCount - 1; i >= 0; i--) {
+ processCpuUsage.threadCpuTimesMillis[i] += cpuUsages[i];
+ if (isSelectedThread) {
+ processCpuUsage.selectedThreadCpuTimesMillis[i] += cpuUsages[i];
+ }
+ }
+ }
+
/** CPU usage of a process, all of its threads and a selected subset of its threads */
public static class ProcessCpuUsage {
+ public long[] processCpuTimesMillis;
public long[] threadCpuTimesMillis;
public long[] selectedThreadCpuTimesMillis;
public ProcessCpuUsage(int cpuFrequencyCount) {
+ processCpuTimesMillis = new long[cpuFrequencyCount];
threadCpuTimesMillis = new long[cpuFrequencyCount];
selectedThreadCpuTimesMillis = new long[cpuFrequencyCount];
}
}
- private native int getCpuFrequencyCount(CpuTimeInStateReader reader);
+ private static boolean isSorted(int[] array) {
+ for (int i = 0; i < array.length - 1; i++) {
+ if (array[i] > array[i + 1]) {
+ return false;
+ }
+ }
+ return true;
+ }
- private native boolean startTrackingProcessCpuTimes(int pid, CpuTimeInStateReader reader);
-
- private native boolean startAggregatingThreadCpuTimes(int[] selectedThreadIds,
- CpuTimeInStateReader reader);
-
- private native boolean readProcessCpuUsage(int pid,
- long[] threadCpuTimesMillis,
- long[] selectedThreadCpuTimesMillis,
- CpuTimeInStateReader reader);
+ private native boolean readProcessCpuUsage(String procPath, int pid, int[] selectedThreadIds,
+ long[] processCpuTimesMillis, long[] threadCpuTimesMillis,
+ long[] selectedThreadCpuTimesMillis);
}
diff --git a/core/java/com/android/internal/os/KernelWakelockReader.java b/core/java/com/android/internal/os/KernelWakelockReader.java
index e595db3..c416814 100644
--- a/core/java/com/android/internal/os/KernelWakelockReader.java
+++ b/core/java/com/android/internal/os/KernelWakelockReader.java
@@ -78,13 +78,16 @@
boolean useSystemSuspend = (new File(sSysClassWakeupDir)).exists();
if (useSystemSuspend) {
- // Get both kernel and native wakelock stats from SystemSuspend
- updateVersion(staleStats);
- if (getWakelockStatsFromSystemSuspend(staleStats) == null) {
- Slog.w(TAG, "Failed to get wakelock stats from SystemSuspend");
- return null;
+ // static read/write lock protection for sKernelWakelockUpdateVersion
+ synchronized (KernelWakelockReader.class) {
+ // Get both kernel and native wakelock stats from SystemSuspend
+ updateVersion(staleStats);
+ if (getWakelockStatsFromSystemSuspend(staleStats) == null) {
+ Slog.w(TAG, "Failed to get wakelock stats from SystemSuspend");
+ return null;
+ }
+ return removeOldStats(staleStats);
}
- return removeOldStats(staleStats);
} else {
Arrays.fill(mKernelWakelockBuffer, (byte) 0);
int len = 0;
@@ -141,14 +144,17 @@
}
}
- updateVersion(staleStats);
- // Get native wakelock stats from SystemSuspend
- if (getWakelockStatsFromSystemSuspend(staleStats) == null) {
- Slog.w(TAG, "Failed to get Native wakelock stats from SystemSuspend");
+ // static read/write lock protection for sKernelWakelockUpdateVersion
+ synchronized (KernelWakelockReader.class) {
+ updateVersion(staleStats);
+ // Get native wakelock stats from SystemSuspend
+ if (getWakelockStatsFromSystemSuspend(staleStats) == null) {
+ Slog.w(TAG, "Failed to get Native wakelock stats from SystemSuspend");
+ }
+ // Get kernel wakelock stats
+ parseProcWakelocks(mKernelWakelockBuffer, len, wakeup_sources, staleStats);
+ return removeOldStats(staleStats);
}
- // Get kernel wakelock stats
- parseProcWakelocks(mKernelWakelockBuffer, len, wakeup_sources, staleStats);
- return removeOldStats(staleStats);
}
}
diff --git a/core/java/com/android/internal/os/SystemServerCpuThreadReader.java b/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
index fbad75e..fbbee94 100644
--- a/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
+++ b/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
@@ -22,6 +22,8 @@
import com.android.internal.annotations.VisibleForTesting;
import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Arrays;
/**
* Reads /proc/UID/task/TID/time_in_state files to obtain statistics on CPU usage
@@ -29,7 +31,9 @@
*/
public class SystemServerCpuThreadReader {
private final KernelSingleProcessCpuThreadReader mKernelCpuThreadReader;
+ private int[] mBinderThreadNativeTids = new int[0]; // Sorted
+ private long[] mLastProcessCpuTimeUs;
private long[] mLastThreadCpuTimesUs;
private long[] mLastBinderThreadCpuTimesUs;
@@ -37,6 +41,8 @@
* Times (in microseconds) spent by the system server UID.
*/
public static class SystemServiceCpuThreadTimes {
+ // The entire process
+ public long[] processCpuTimesUs;
// All threads
public long[] threadCpuTimesUs;
// Just the threads handling incoming binder calls
@@ -55,10 +61,8 @@
}
@VisibleForTesting
- public SystemServerCpuThreadReader(int pid,
- KernelSingleProcessCpuThreadReader.CpuTimeInStateReader cpuTimeInStateReader)
- throws IOException {
- this(new KernelSingleProcessCpuThreadReader(pid, cpuTimeInStateReader));
+ public SystemServerCpuThreadReader(Path procPath, int pid) throws IOException {
+ this(new KernelSingleProcessCpuThreadReader(pid, procPath));
}
@VisibleForTesting
@@ -66,15 +70,9 @@
mKernelCpuThreadReader = kernelCpuThreadReader;
}
- /**
- * Start tracking CPU time-in-state for the process specified in the constructor.
- */
- public void startTrackingThreadCpuTime() {
- mKernelCpuThreadReader.startTrackingThreadCpuTimes();
- }
-
public void setBinderThreadNativeTids(int[] nativeTids) {
- mKernelCpuThreadReader.setSelectedThreadIds(nativeTids);
+ mBinderThreadNativeTids = nativeTids.clone();
+ Arrays.sort(mBinderThreadNativeTids);
}
/**
@@ -83,27 +81,33 @@
@Nullable
public SystemServiceCpuThreadTimes readDelta() {
final int numCpuFrequencies = mKernelCpuThreadReader.getCpuFrequencyCount();
- if (mLastThreadCpuTimesUs == null) {
+ if (mLastProcessCpuTimeUs == null) {
+ mLastProcessCpuTimeUs = new long[numCpuFrequencies];
mLastThreadCpuTimesUs = new long[numCpuFrequencies];
mLastBinderThreadCpuTimesUs = new long[numCpuFrequencies];
+ mDeltaCpuThreadTimes.processCpuTimesUs = new long[numCpuFrequencies];
mDeltaCpuThreadTimes.threadCpuTimesUs = new long[numCpuFrequencies];
mDeltaCpuThreadTimes.binderThreadCpuTimesUs = new long[numCpuFrequencies];
}
final KernelSingleProcessCpuThreadReader.ProcessCpuUsage processCpuUsage =
- mKernelCpuThreadReader.getProcessCpuUsage();
+ mKernelCpuThreadReader.getProcessCpuUsage(mBinderThreadNativeTids);
if (processCpuUsage == null) {
return null;
}
for (int i = numCpuFrequencies - 1; i >= 0; i--) {
+ long processCpuTimesUs = processCpuUsage.processCpuTimesMillis[i] * 1000;
long threadCpuTimesUs = processCpuUsage.threadCpuTimesMillis[i] * 1000;
long binderThreadCpuTimesUs = processCpuUsage.selectedThreadCpuTimesMillis[i] * 1000;
+ mDeltaCpuThreadTimes.processCpuTimesUs[i] =
+ Math.max(0, processCpuTimesUs - mLastProcessCpuTimeUs[i]);
mDeltaCpuThreadTimes.threadCpuTimesUs[i] =
Math.max(0, threadCpuTimesUs - mLastThreadCpuTimesUs[i]);
mDeltaCpuThreadTimes.binderThreadCpuTimesUs[i] =
Math.max(0, binderThreadCpuTimesUs - mLastBinderThreadCpuTimesUs[i]);
+ mLastProcessCpuTimeUs[i] = processCpuTimesUs;
mLastThreadCpuTimesUs[i] = threadCpuTimesUs;
mLastBinderThreadCpuTimesUs[i] = binderThreadCpuTimesUs;
}
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 5e20cd0..fda87be 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -24,7 +24,6 @@
import android.net.Credentials;
import android.net.LocalServerSocket;
import android.net.LocalSocket;
-import android.net.NetworkUtils;
import android.os.FactoryTest;
import android.os.IVold;
import android.os.Process;
@@ -35,6 +34,8 @@
import android.system.Os;
import android.util.Log;
+import com.android.internal.net.NetworkUtilsInternal;
+
import dalvik.annotation.optimization.FastNative;
import dalvik.system.ZygoteHooks;
@@ -340,7 +341,7 @@
// If no GIDs were specified, don't make any permissions changes based on groups.
if (gids != null && gids.length > 0) {
- NetworkUtils.setAllowNetworkingForProcess(containsInetGid(gids));
+ NetworkUtilsInternal.setAllowNetworkingForProcess(containsInetGid(gids));
}
}
diff --git a/core/java/com/android/internal/util/BinaryXmlPullParser.java b/core/java/com/android/internal/util/BinaryXmlPullParser.java
index 68921ad..57552f3 100644
--- a/core/java/com/android/internal/util/BinaryXmlPullParser.java
+++ b/core/java/com/android/internal/util/BinaryXmlPullParser.java
@@ -95,8 +95,8 @@
private Attribute[] mAttributes;
@Override
- public void setInput(InputStream is, String inputEncoding) throws XmlPullParserException {
- if (inputEncoding != null && !StandardCharsets.UTF_8.name().equals(inputEncoding)) {
+ public void setInput(InputStream is, String encoding) throws XmlPullParserException {
+ if (encoding != null && !StandardCharsets.UTF_8.name().equalsIgnoreCase(encoding)) {
throw new UnsupportedOperationException();
}
@@ -262,19 +262,27 @@
break;
}
case XmlPullParser.START_DOCUMENT: {
+ mCurrentName = null;
+ mCurrentText = null;
+ if (mAttributeCount > 0) resetAttributes();
break;
}
case XmlPullParser.END_DOCUMENT: {
+ mCurrentName = null;
+ mCurrentText = null;
+ if (mAttributeCount > 0) resetAttributes();
break;
}
case XmlPullParser.START_TAG: {
mCurrentName = mIn.readInternedUTF();
- resetAttributes();
+ mCurrentText = null;
+ if (mAttributeCount > 0) resetAttributes();
break;
}
case XmlPullParser.END_TAG: {
mCurrentName = mIn.readInternedUTF();
- resetAttributes();
+ mCurrentText = null;
+ if (mAttributeCount > 0) resetAttributes();
break;
}
case XmlPullParser.TEXT:
@@ -283,12 +291,15 @@
case XmlPullParser.COMMENT:
case XmlPullParser.DOCDECL:
case XmlPullParser.IGNORABLE_WHITESPACE: {
+ mCurrentName = null;
mCurrentText = mIn.readUTF();
+ if (mAttributeCount > 0) resetAttributes();
break;
}
case XmlPullParser.ENTITY_REF: {
mCurrentName = mIn.readUTF();
mCurrentText = resolveEntity(mCurrentName);
+ if (mAttributeCount > 0) resetAttributes();
break;
}
default: {
@@ -428,7 +439,11 @@
@Override
public String getAttributeValue(String namespace, String name) {
final int index = getAttributeIndex(namespace, name);
- return mAttributes[index].getValueString();
+ if (index != -1) {
+ return mAttributes[index].getValueString();
+ } else {
+ return null;
+ }
}
@Override
diff --git a/core/java/com/android/internal/util/BinaryXmlSerializer.java b/core/java/com/android/internal/util/BinaryXmlSerializer.java
index bc3b1f8..9df4bdb 100644
--- a/core/java/com/android/internal/util/BinaryXmlSerializer.java
+++ b/core/java/com/android/internal/util/BinaryXmlSerializer.java
@@ -120,7 +120,7 @@
@Override
public void setOutput(@NonNull OutputStream os, @Nullable String encoding) throws IOException {
- if (encoding != null && !StandardCharsets.UTF_8.name().equals(encoding)) {
+ if (encoding != null && !StandardCharsets.UTF_8.name().equalsIgnoreCase(encoding)) {
throw new UnsupportedOperationException();
}
@@ -144,7 +144,10 @@
@Override
public void startDocument(@Nullable String encoding, @Nullable Boolean standalone)
throws IOException {
- if (encoding != null && !StandardCharsets.UTF_8.name().equals(encoding)) {
+ if (encoding != null && !StandardCharsets.UTF_8.name().equalsIgnoreCase(encoding)) {
+ throw new UnsupportedOperationException();
+ }
+ if (standalone != null && !standalone) {
throw new UnsupportedOperationException();
}
mOut.writeByte(START_DOCUMENT | TYPE_NULL);
diff --git a/core/java/com/android/internal/util/OWNERS b/core/java/com/android/internal/util/OWNERS
index 8b9acd3..a045451 100644
--- a/core/java/com/android/internal/util/OWNERS
+++ b/core/java/com/android/internal/util/OWNERS
@@ -2,3 +2,4 @@
per-file MessageUtils*, Protocol*, RingBuffer*, TokenBucket* = jchalard@google.com, lorenzo@google.com, satk@google.com
per-file Protocol* = etancohen@google.com, lorenzo@google.com
per-file State* = jchalard@google.com, lorenzo@google.com, satk@google.com
+per-file DataClass* = eugenesusla@google.com
\ No newline at end of file
diff --git a/core/java/com/android/internal/util/XmlSerializerWrapper.java b/core/java/com/android/internal/util/XmlSerializerWrapper.java
index 2131db0..9f28d90a 100644
--- a/core/java/com/android/internal/util/XmlSerializerWrapper.java
+++ b/core/java/com/android/internal/util/XmlSerializerWrapper.java
@@ -28,7 +28,7 @@
/**
* Wrapper which delegates all calls through to the given {@link XmlSerializer}.
*/
-public class XmlSerializerWrapper {
+public class XmlSerializerWrapper implements XmlSerializer {
private final XmlSerializer mWrapped;
public XmlSerializerWrapper(@NonNull XmlSerializer wrapped) {
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 8962dc3..ef2275d 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -158,10 +158,6 @@
}
@Override
- public void dispatchPointerCaptureChanged(boolean hasCapture) {
- }
-
- @Override
public void requestScrollCapture(IScrollCaptureCallbacks callbacks) {
try {
callbacks.onUnavailable();
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 455e489..1fadfc5 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -26,6 +26,10 @@
import com.android.internal.view.IInputMethodClient;
import com.android.internal.inputmethod.IBooleanResultCallback;
import com.android.internal.inputmethod.IInputBindResultResultCallback;
+import com.android.internal.inputmethod.IInputMethodInfoListResultCallback;
+import com.android.internal.inputmethod.IInputMethodSubtypeResultCallback;
+import com.android.internal.inputmethod.IInputMethodSubtypeListResultCallback;
+import com.android.internal.inputmethod.IIntResultCallback;
/**
* Public interface to the global input method manager, used by all client
@@ -36,12 +40,13 @@
int untrustedDisplayId);
// TODO: Use ParceledListSlice instead
- List<InputMethodInfo> getInputMethodList(int userId);
+ void getInputMethodList(int userId, in IInputMethodInfoListResultCallback resultCallback);
// TODO: Use ParceledListSlice instead
- List<InputMethodInfo> getEnabledInputMethodList(int userId);
- List<InputMethodSubtype> getEnabledInputMethodSubtypeList(in String imiId,
- boolean allowsImplicitlySelectedSubtypes);
- InputMethodSubtype getLastInputMethodSubtype();
+ void getEnabledInputMethodList(int userId,
+ in IInputMethodInfoListResultCallback resultCallback);
+ void getEnabledInputMethodSubtypeList(in String imiId, boolean allowsImplicitlySelectedSubtypes,
+ in IInputMethodSubtypeListResultCallback resultCallback);
+ void getLastInputMethodSubtype(in IInputMethodSubtypeResultCallback resultCallback);
void showSoftInput(in IInputMethodClient client, IBinder windowToken, int flags,
in ResultReceiver resultReceiver, in IBooleanResultCallback resultCallback);
@@ -66,11 +71,11 @@
int displayId);
void showInputMethodAndSubtypeEnablerFromClient(in IInputMethodClient client, String topId);
void isInputMethodPickerShownForTest(in IBooleanResultCallback resultCallback);
- InputMethodSubtype getCurrentInputMethodSubtype();
+ void getCurrentInputMethodSubtype(in IInputMethodSubtypeResultCallback resultCallback);
void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
// This is kept due to @UnsupportedAppUsage.
// TODO(Bug 113914148): Consider removing this.
- int getInputMethodWindowVisibleHeight();
+ void getInputMethodWindowVisibleHeight(IIntResultCallback resultCallback);
void reportActivityView(in IInputMethodClient parentClient, int childDisplayId,
in float[] matrixValues);
diff --git a/core/java/com/android/server/net/BaseNetworkObserver.java b/core/java/com/android/server/net/BaseNetworkObserver.java
index 2a9c0b4..0e8d61a 100644
--- a/core/java/com/android/server/net/BaseNetworkObserver.java
+++ b/core/java/com/android/server/net/BaseNetworkObserver.java
@@ -64,7 +64,8 @@
}
@Override
- public void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos) {
+ public void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos,
+ int uid) {
// default no-op
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 8c83d7c..c05e7a2 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -181,6 +181,7 @@
"android_content_res_Configuration.cpp",
"android_security_Scrypt.cpp",
"com_android_internal_content_om_OverlayConfig.cpp",
+ "com_android_internal_net_NetworkUtilsInternal.cpp",
"com_android_internal_os_ClassLoaderFactory.cpp",
"com_android_internal_os_FuseAppLoop.cpp",
"com_android_internal_os_KernelCpuUidBpfMapReader.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 14e74a8..cefa88c 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -187,6 +187,7 @@
extern int register_android_security_Scrypt(JNIEnv *env);
extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
extern int register_com_android_internal_content_om_OverlayConfig(JNIEnv *env);
+extern int register_com_android_internal_net_NetworkUtilsInternal(JNIEnv* env);
extern int register_com_android_internal_os_ClassLoaderFactory(JNIEnv* env);
extern int register_com_android_internal_os_FuseAppLoop(JNIEnv* env);
extern int register_com_android_internal_os_KernelCpuUidBpfMapReader(JNIEnv *env);
@@ -1522,6 +1523,7 @@
REG_JNI(register_android_os_SharedMemory),
REG_JNI(register_android_os_incremental_IncrementalManager),
REG_JNI(register_com_android_internal_content_om_OverlayConfig),
+ REG_JNI(register_com_android_internal_net_NetworkUtilsInternal),
REG_JNI(register_com_android_internal_os_ClassLoaderFactory),
REG_JNI(register_com_android_internal_os_Zygote),
REG_JNI(register_com_android_internal_os_ZygoteInit),
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
index 444bb66..66753e4 100644
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ b/core/jni/android_content_res_ApkAssets.cpp
@@ -315,10 +315,14 @@
return reinterpret_cast<jlong>(apk_assets.release());
}
-static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
+static void NativeDestroy(void* ptr) {
delete reinterpret_cast<ApkAssets*>(ptr);
}
+static jlong NativeGetFinalizer(JNIEnv* /*env*/, jclass /*clazz*/) {
+ return reinterpret_cast<jlong>(&NativeDestroy);
+}
+
static jstring NativeGetAssetPath(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
return env->NewStringUTF(apk_assets->GetPath().c_str());
@@ -427,7 +431,7 @@
{"nativeLoadFdOffsets",
"(ILjava/io/FileDescriptor;Ljava/lang/String;JJILandroid/content/res/loader/AssetsProvider;)J",
(void*)NativeLoadFromFdOffset},
- {"nativeDestroy", "(J)V", (void*)NativeDestroy},
+ {"nativeGetFinalizer", "()J", (void*)NativeGetFinalizer},
{"nativeGetAssetPath", "(J)Ljava/lang/String;", (void*)NativeGetAssetPath},
{"nativeGetStringBlock", "(J)J", (void*)NativeGetStringBlock},
{"nativeIsUpToDate", "(J)Z", (void*)NativeIsUpToDate},
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index a95ee4f..5cffbef 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -298,20 +298,25 @@
return old;
}
-#define check_AudioSystem_Command(status) _check_AudioSystem_Command(__func__, (status))
+#define check_AudioSystem_Command(...) _check_AudioSystem_Command(__func__, __VA_ARGS__)
-static int _check_AudioSystem_Command(const char* caller, status_t status)
-{
- ALOGE_IF(status, "Command failed for %s: %d", caller, status);
+static int _check_AudioSystem_Command(const char *caller, status_t status,
+ std::vector<status_t> ignoredErrors = {}) {
+ int jniStatus = kAudioStatusOk;
switch (status) {
case DEAD_OBJECT:
- return kAudioStatusMediaServerDied;
+ jniStatus = kAudioStatusMediaServerDied;
+ break;
case NO_ERROR:
- return kAudioStatusOk;
+ break;
default:
+ if (std::find(begin(ignoredErrors), end(ignoredErrors), status) == end(ignoredErrors)) {
+ jniStatus = kAudioStatusError;
+ }
break;
}
- return kAudioStatusError;
+ ALOGE_IF(jniStatus != kAudioStatusOk, "Command failed for %s: %d", caller, status);
+ return jniStatus;
}
static jint getVectorOfAudioDeviceTypeAddr(JNIEnv *env, jintArray deviceTypes,
@@ -2350,9 +2355,12 @@
static jint android_media_AudioSystem_removeDevicesRoleForStrategy(JNIEnv *env, jobject thiz,
jint strategy, jint role) {
- return (jint)check_AudioSystem_Command(
- AudioSystem::removeDevicesRoleForStrategy((product_strategy_t)strategy,
- (device_role_t)role));
+ return (jint)
+ check_AudioSystem_Command(AudioSystem::removeDevicesRoleForStrategy((product_strategy_t)
+ strategy,
+ (device_role_t)
+ role),
+ {NAME_NOT_FOUND});
}
static jint android_media_AudioSystem_getDevicesForRoleAndStrategy(JNIEnv *env, jobject thiz,
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 8d4c4e5..2155246 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2008, The Android Open Source Project
+ * Copyright 2020, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,7 +28,6 @@
#include <netinet/udp.h>
#include <DnsProxydProtocol.h> // NETID_USE_LOCAL_NAMESERVERS
-#include <android_runtime/AndroidRuntime.h>
#include <cutils/properties.h>
#include <nativehelper/JNIPlatformHelp.h>
#include <nativehelper/ScopedLocalRef.h>
@@ -226,11 +225,6 @@
class_Network, ctor, dnsNetId & ~NETID_USE_LOCAL_NAMESERVERS, privateDnsBypass);
}
-static void android_net_utils_setAllowNetworkingForProcess(JNIEnv *env, jobject thiz,
- jboolean hasConnectivity) {
- setAllowNetworkingForProcess(hasConnectivity == JNI_TRUE);
-}
-
static jobject android_net_utils_getTcpRepairWindow(JNIEnv *env, jobject thiz, jobject javaFd) {
if (javaFd == NULL) {
jniThrowNullPointerException(env, NULL);
@@ -288,7 +282,6 @@
{ "resNetworkResult", "(Ljava/io/FileDescriptor;)Landroid/net/DnsResolver$DnsResponse;", (void*) android_net_utils_resNetworkResult },
{ "resNetworkCancel", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_resNetworkCancel },
{ "getDnsNetwork", "()Landroid/net/Network;", (void*) android_net_utils_getDnsNetwork },
- { "setAllowNetworkingForProcess", "(Z)V", (void *)android_net_utils_setAllowNetworkingForProcess },
};
// clang-format on
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index bf79a44..bb51c57 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -847,6 +847,17 @@
return ionPss;
}
+static jlong android_os_Debug_getGpuTotalUsageKb(JNIEnv* env, jobject clazz) {
+ jlong sizeKb = -1;
+ uint64_t size;
+
+ if (meminfo::ReadGpuTotalUsageKb(&size)) {
+ sizeKb = size;
+ }
+
+ return sizeKb;
+}
+
static jboolean android_os_Debug_isVmapStack(JNIEnv *env, jobject clazz)
{
static enum {
@@ -915,6 +926,8 @@
(void*)android_os_Debug_getIonPoolsSizeKb },
{ "getIonMappedSizeKb", "()J",
(void*)android_os_Debug_getIonMappedSizeKb },
+ { "getGpuTotalUsageKb", "()J",
+ (void*)android_os_Debug_getGpuTotalUsageKb },
{ "isVmapStack", "()Z",
(void*)android_os_Debug_isVmapStack },
};
diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp
index 9f4e3e5..4eaa016 100644
--- a/core/jni/android_view_InputDevice.cpp
+++ b/core/jni/android_view_InputDevice.cpp
@@ -60,13 +60,17 @@
// Not sure why, but JNI is complaining when I pass this through directly.
jboolean hasMic = deviceInfo.hasMic() ? JNI_TRUE : JNI_FALSE;
- ScopedLocalRef<jobject> inputDeviceObj(env, env->NewObject(gInputDeviceClassInfo.clazz,
- gInputDeviceClassInfo.ctor, deviceInfo.getId(), deviceInfo.getGeneration(),
- deviceInfo.getControllerNumber(), nameObj.get(),
- static_cast<int32_t>(ident.vendor), static_cast<int32_t>(ident.product),
- descriptorObj.get(), deviceInfo.isExternal(), deviceInfo.getSources(),
- deviceInfo.getKeyboardType(), kcmObj.get(), deviceInfo.hasVibrator(),
- hasMic, deviceInfo.hasButtonUnderPad()));
+ ScopedLocalRef<jobject>
+ inputDeviceObj(env,
+ env->NewObject(gInputDeviceClassInfo.clazz, gInputDeviceClassInfo.ctor,
+ deviceInfo.getId(), deviceInfo.getGeneration(),
+ deviceInfo.getControllerNumber(), nameObj.get(),
+ static_cast<int32_t>(ident.vendor),
+ static_cast<int32_t>(ident.product), descriptorObj.get(),
+ deviceInfo.isExternal(), deviceInfo.getSources(),
+ deviceInfo.getKeyboardType(), kcmObj.get(),
+ deviceInfo.hasVibrator(), hasMic,
+ deviceInfo.hasButtonUnderPad(), deviceInfo.hasSensor()));
const std::vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
for (const InputDeviceInfo::MotionRange& range: ranges) {
@@ -87,7 +91,8 @@
gInputDeviceClassInfo.clazz = MakeGlobalRefOrDie(env, gInputDeviceClassInfo.clazz);
gInputDeviceClassInfo.ctor = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "<init>",
- "(IIILjava/lang/String;IILjava/lang/String;ZIILandroid/view/KeyCharacterMap;ZZZ)V");
+ "(IIILjava/lang/String;IILjava/lang/"
+ "String;ZIILandroid/view/KeyCharacterMap;ZZZZ)V");
gInputDeviceClassInfo.addMotionRange = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz,
"addMotionRange", "(IIFFFFF)V");
diff --git a/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp b/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp
new file mode 100644
index 0000000..10fc18d
--- /dev/null
+++ b/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "NetdClient.h"
+#include "core_jni_helpers.h"
+#include "jni.h"
+
+namespace android {
+static void android_net_utils_setAllowNetworkingForProcess(JNIEnv *env, jobject thiz,
+ jboolean hasConnectivity) {
+ setAllowNetworkingForProcess(hasConnectivity == JNI_TRUE);
+}
+
+static const JNINativeMethod gNetworkUtilMethods[] = {
+ {"setAllowNetworkingForProcess", "(Z)V",
+ (void *)android_net_utils_setAllowNetworkingForProcess},
+};
+
+int register_com_android_internal_net_NetworkUtilsInternal(JNIEnv *env) {
+ return RegisterMethodsOrDie(env, "com/android/internal/net/NetworkUtilsInternal",
+ gNetworkUtilMethods, NELEM(gNetworkUtilMethods));
+}
+
+} // namespace android
diff --git a/core/jni/com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp b/core/jni/com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp
index dfae684..52bed6b 100644
--- a/core/jni/com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp
+++ b/core/jni/com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp
@@ -26,230 +26,239 @@
#include <android_runtime/Log.h>
#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/ScopedUtfChars.h>
namespace android {
-static constexpr uint16_t DEFAULT_THREAD_AGGREGATION_KEY = 0;
-static constexpr uint16_t SELECTED_THREAD_AGGREGATION_KEY = 1;
-
-static constexpr uint64_t NSEC_PER_MSEC = 1000000;
-
// Number of milliseconds in a jiffy - the unit of time measurement for processes and threads
static const uint32_t gJiffyMillis = (uint32_t)(1000 / sysconf(_SC_CLK_TCK));
-// Abstract class for readers of CPU time-in-state. There are two implementations of
-// this class: BpfCpuTimeInStateReader and MockCpuTimeInStateReader. The former is used
-// by the production code. The latter is used by unit tests to provide mock
-// CPU time-in-state data via a Java implementation.
-class ICpuTimeInStateReader {
-public:
- virtual ~ICpuTimeInStateReader() {}
+// Given a PID, returns a vector of all TIDs for the process' tasks. Thread IDs are
+// file names in the /proc/<pid>/task directory.
+static bool getThreadIds(const std::string &procPath, const pid_t pid,
+ std::vector<pid_t> &outThreadIds) {
+ std::string taskPath = android::base::StringPrintf("%s/%u/task", procPath.c_str(), pid);
- // Returns the overall number of cluser-frequency combinations
- virtual size_t getCpuFrequencyCount();
+ struct dirent **dirlist;
+ int threadCount = scandir(taskPath.c_str(), &dirlist, NULL, NULL);
+ if (threadCount == -1) {
+ ALOGE("Cannot read directory %s", taskPath.c_str());
+ return false;
+ }
- // Marks the CPU time-in-state tracking for threads of the specified TGID
- virtual bool startTrackingProcessCpuTimes(pid_t) = 0;
+ outThreadIds.reserve(threadCount);
- // Marks the thread specified by its PID for CPU time-in-state tracking.
- virtual bool startAggregatingTaskCpuTimes(pid_t, uint16_t) = 0;
+ for (int i = 0; i < threadCount; i++) {
+ pid_t tid;
+ if (android::base::ParseInt<pid_t>(dirlist[i]->d_name, &tid)) {
+ outThreadIds.push_back(tid);
+ }
+ free(dirlist[i]);
+ }
+ free(dirlist);
- // Retrieves the accumulated time-in-state data, which is organized as a map
- // from aggregation keys to vectors of vectors using the format:
- // { aggKey0 -> [[t0_0_0, t0_0_1, ...], [t0_1_0, t0_1_1, ...], ...],
- // aggKey1 -> [[t1_0_0, t1_0_1, ...], [t1_1_0, t1_1_1, ...], ...], ... }
- // where ti_j_k is the ns tid i spent running on the jth cluster at the cluster's kth lowest
- // freq.
- virtual std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>>
- getAggregatedTaskCpuFreqTimes(pid_t, const std::vector<uint16_t> &);
-};
+ return true;
+}
-// ICpuTimeInStateReader that uses eBPF to provide a map of aggregated CPU time-in-state values.
-// See cputtimeinstate.h/.cpp
-class BpfCpuTimeInStateReader : public ICpuTimeInStateReader {
-public:
- size_t getCpuFrequencyCount() {
- std::optional<std::vector<std::vector<uint32_t>>> cpuFreqs = android::bpf::getCpuFreqs();
- if (!cpuFreqs) {
- ALOGE("Cannot obtain CPU frequency count");
- return 0;
+// Reads contents of a time_in_state file and returns times as a vector of times per frequency
+// A time_in_state file contains pairs of frequency - time (in jiffies):
+//
+// cpu0
+// 300000 30
+// 403200 0
+// cpu4
+// 710400 10
+// 825600 20
+// 940800 30
+//
+static bool getThreadTimeInState(const std::string &procPath, const pid_t pid, const pid_t tid,
+ const size_t frequencyCount,
+ std::vector<uint64_t> &outThreadTimeInState) {
+ std::string timeInStateFilePath =
+ android::base::StringPrintf("%s/%u/task/%u/time_in_state", procPath.c_str(), pid, tid);
+ std::string data;
+
+ if (!android::base::ReadFileToString(timeInStateFilePath, &data)) {
+ ALOGE("Cannot read file: %s", timeInStateFilePath.c_str());
+ return false;
+ }
+
+ auto lines = android::base::Split(data, "\n");
+ size_t index = 0;
+ for (const auto &line : lines) {
+ if (line.empty()) {
+ continue;
}
- size_t freqCount = 0;
- for (auto cluster : *cpuFreqs) {
- freqCount += cluster.size();
+ auto numbers = android::base::Split(line, " ");
+ if (numbers.size() != 2) {
+ continue;
}
-
- return freqCount;
- }
-
- bool startTrackingProcessCpuTimes(pid_t tgid) {
- return android::bpf::startTrackingProcessCpuTimes(tgid);
- }
-
- bool startAggregatingTaskCpuTimes(pid_t pid, uint16_t aggregationKey) {
- return android::bpf::startAggregatingTaskCpuTimes(pid, aggregationKey);
- }
-
- std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>>
- getAggregatedTaskCpuFreqTimes(pid_t pid, const std::vector<uint16_t> &aggregationKeys) {
- return android::bpf::getAggregatedTaskCpuFreqTimes(pid, aggregationKeys);
- }
-};
-
-// ICpuTimeInStateReader that uses JNI to provide a map of aggregated CPU time-in-state
-// values.
-// This version of CpuTimeInStateReader is used exclusively for providing mock data in tests.
-class MockCpuTimeInStateReader : public ICpuTimeInStateReader {
-private:
- JNIEnv *mEnv;
- jobject mCpuTimeInStateReader;
-
-public:
- MockCpuTimeInStateReader(JNIEnv *env, jobject cpuTimeInStateReader)
- : mEnv(env), mCpuTimeInStateReader(cpuTimeInStateReader) {}
-
- size_t getCpuFrequencyCount();
-
- bool startTrackingProcessCpuTimes(pid_t tgid);
-
- bool startAggregatingTaskCpuTimes(pid_t pid, uint16_t aggregationKey);
-
- std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>>
- getAggregatedTaskCpuFreqTimes(pid_t tgid, const std::vector<uint16_t> &aggregationKeys);
-};
-
-static ICpuTimeInStateReader *getCpuTimeInStateReader(JNIEnv *env,
- jobject cpuTimeInStateReaderObject) {
- if (cpuTimeInStateReaderObject) {
- return new MockCpuTimeInStateReader(env, cpuTimeInStateReaderObject);
- } else {
- return new BpfCpuTimeInStateReader();
- }
-}
-
-static jint getCpuFrequencyCount(JNIEnv *env, jclass, jobject cpuTimeInStateReaderObject) {
- std::unique_ptr<ICpuTimeInStateReader> cpuTimeInStateReader(
- getCpuTimeInStateReader(env, cpuTimeInStateReaderObject));
- return cpuTimeInStateReader->getCpuFrequencyCount();
-}
-
-static jboolean startTrackingProcessCpuTimes(JNIEnv *env, jclass, jint tgid,
- jobject cpuTimeInStateReaderObject) {
- std::unique_ptr<ICpuTimeInStateReader> cpuTimeInStateReader(
- getCpuTimeInStateReader(env, cpuTimeInStateReaderObject));
- return cpuTimeInStateReader->startTrackingProcessCpuTimes(tgid);
-}
-
-static jboolean startAggregatingThreadCpuTimes(JNIEnv *env, jclass, jintArray selectedThreadIdArray,
- jobject cpuTimeInStateReaderObject) {
- ScopedIntArrayRO selectedThreadIds(env, selectedThreadIdArray);
- std::unique_ptr<ICpuTimeInStateReader> cpuTimeInStateReader(
- getCpuTimeInStateReader(env, cpuTimeInStateReaderObject));
-
- for (int i = 0; i < selectedThreadIds.size(); i++) {
- if (!cpuTimeInStateReader->startAggregatingTaskCpuTimes(selectedThreadIds[i],
- SELECTED_THREAD_AGGREGATION_KEY)) {
+ uint64_t timeInState;
+ if (!android::base::ParseUint<uint64_t>(numbers[1], &timeInState)) {
+ ALOGE("Invalid time_in_state file format: %s", timeInStateFilePath.c_str());
return false;
}
- }
- return true;
-}
-
-// Converts time-in-state data from a vector of vectors to a flat array.
-// Also converts from nanoseconds to milliseconds.
-static bool flattenTimeInStateData(ScopedLongArrayRW &cpuTimesMillis,
- const std::vector<std::vector<uint64_t>> &data) {
- size_t frequencyCount = cpuTimesMillis.size();
- size_t index = 0;
- for (const auto &cluster : data) {
- for (const uint64_t &timeNanos : cluster) {
- if (index < frequencyCount) {
- cpuTimesMillis[index] = timeNanos / NSEC_PER_MSEC;
- }
- index++;
+ if (index < frequencyCount) {
+ outThreadTimeInState[index] = timeInState;
}
+ index++;
}
+
if (index != frequencyCount) {
- ALOGE("CPU time-in-state reader returned data for %zu frequencies; expected: %zu", index,
- frequencyCount);
+ ALOGE("Incorrect number of frequencies %u in %s. Expected %u",
+ (uint32_t)outThreadTimeInState.size(), timeInStateFilePath.c_str(),
+ (uint32_t)frequencyCount);
return false;
}
return true;
}
-// Reads all CPU time-in-state data accumulated by BPF and aggregates per-frequency
+static int pidCompare(const void *a, const void *b) {
+ return (*(pid_t *)a - *(pid_t *)b);
+}
+
+static inline bool isSelectedThread(const pid_t tid, const pid_t *selectedThreadIds,
+ const size_t selectedThreadCount) {
+ return bsearch(&tid, selectedThreadIds, selectedThreadCount, sizeof(pid_t), pidCompare) != NULL;
+}
+
+// Reads all /proc/<pid>/task/*/time_in_state files and aggregates per-frequency
// time in state data for all threads. Also, separately aggregates time in state for
// selected threads whose TIDs are passes as selectedThreadIds.
-static jboolean readProcessCpuUsage(JNIEnv *env, jclass, jint pid,
+static void aggregateThreadCpuTimes(const std::string &procPath, const pid_t pid,
+ const std::vector<pid_t> &threadIds,
+ const size_t frequencyCount, const pid_t *selectedThreadIds,
+ const size_t selectedThreadCount,
+ uint64_t *threadCpuTimesMillis,
+ uint64_t *selectedThreadCpuTimesMillis) {
+ for (size_t j = 0; j < frequencyCount; j++) {
+ threadCpuTimesMillis[j] = 0;
+ selectedThreadCpuTimesMillis[j] = 0;
+ }
+
+ for (size_t i = 0; i < threadIds.size(); i++) {
+ pid_t tid = threadIds[i];
+ std::vector<uint64_t> timeInState(frequencyCount);
+ if (!getThreadTimeInState(procPath, pid, tid, frequencyCount, timeInState)) {
+ continue;
+ }
+
+ bool selectedThread = isSelectedThread(tid, selectedThreadIds, selectedThreadCount);
+ for (size_t j = 0; j < frequencyCount; j++) {
+ threadCpuTimesMillis[j] += timeInState[j];
+ if (selectedThread) {
+ selectedThreadCpuTimesMillis[j] += timeInState[j];
+ }
+ }
+ }
+ for (size_t i = 0; i < frequencyCount; i++) {
+ threadCpuTimesMillis[i] *= gJiffyMillis;
+ selectedThreadCpuTimesMillis[i] *= gJiffyMillis;
+ }
+}
+
+// Reads process utime and stime from the /proc/<pid>/stat file.
+// Format of this file is described in https://man7.org/linux/man-pages/man5/proc.5.html.
+static bool getProcessCpuTime(const std::string &procPath, const pid_t pid,
+ uint64_t &outTimeMillis) {
+ std::string statFilePath = android::base::StringPrintf("%s/%u/stat", procPath.c_str(), pid);
+ std::string data;
+ if (!android::base::ReadFileToString(statFilePath, &data)) {
+ return false;
+ }
+
+ auto fields = android::base::Split(data, " ");
+ uint64_t utime, stime;
+
+ // Field 14 (counting from 1) is utime - process time in user space, in jiffies
+ // Field 15 (counting from 1) is stime - process time in system space, in jiffies
+ if (fields.size() < 15 || !android::base::ParseUint(fields[13], &utime) ||
+ !android::base::ParseUint(fields[14], &stime)) {
+ ALOGE("Invalid file format %s", statFilePath.c_str());
+ return false;
+ }
+
+ outTimeMillis = (utime + stime) * gJiffyMillis;
+ return true;
+}
+
+// Estimates per cluster per frequency CPU time for the entire process
+// by distributing the total process CPU time proportionately to how much
+// CPU time its threads took on those clusters/frequencies. This algorithm
+// works more accurately when when we have equally distributed concurrency.
+// TODO(b/169279846): obtain actual process CPU times from the kernel
+static void estimateProcessTimeInState(const uint64_t processCpuTimeMillis,
+ const uint64_t *threadCpuTimesMillis,
+ const size_t frequencyCount,
+ uint64_t *processCpuTimesMillis) {
+ uint64_t totalCpuTimeAllThreads = 0;
+ for (size_t i = 0; i < frequencyCount; i++) {
+ totalCpuTimeAllThreads += threadCpuTimesMillis[i];
+ }
+
+ if (totalCpuTimeAllThreads != 0) {
+ for (size_t i = 0; i < frequencyCount; i++) {
+ processCpuTimesMillis[i] =
+ processCpuTimeMillis * threadCpuTimesMillis[i] / totalCpuTimeAllThreads;
+ }
+ } else {
+ for (size_t i = 0; i < frequencyCount; i++) {
+ processCpuTimesMillis[i] = 0;
+ }
+ }
+}
+
+static jboolean readProcessCpuUsage(JNIEnv *env, jclass, jstring procPath, jint pid,
+ jintArray selectedThreadIdArray,
+ jlongArray processCpuTimesMillisArray,
jlongArray threadCpuTimesMillisArray,
- jlongArray selectedThreadCpuTimesMillisArray,
- jobject cpuTimeInStateReaderObject) {
+ jlongArray selectedThreadCpuTimesMillisArray) {
+ ScopedUtfChars procPathChars(env, procPath);
+ ScopedIntArrayRO selectedThreadIds(env, selectedThreadIdArray);
+ ScopedLongArrayRW processCpuTimesMillis(env, processCpuTimesMillisArray);
ScopedLongArrayRW threadCpuTimesMillis(env, threadCpuTimesMillisArray);
ScopedLongArrayRW selectedThreadCpuTimesMillis(env, selectedThreadCpuTimesMillisArray);
- std::unique_ptr<ICpuTimeInStateReader> cpuTimeInStateReader(
- getCpuTimeInStateReader(env, cpuTimeInStateReaderObject));
- const size_t frequencyCount = cpuTimeInStateReader->getCpuFrequencyCount();
+ std::string procPathStr(procPathChars.c_str());
+
+ // Get all thread IDs for the process.
+ std::vector<pid_t> threadIds;
+ if (!getThreadIds(procPathStr, pid, threadIds)) {
+ ALOGE("Could not obtain thread IDs from: %s", procPathStr.c_str());
+ return false;
+ }
+
+ size_t frequencyCount = processCpuTimesMillis.size();
if (threadCpuTimesMillis.size() != frequencyCount) {
- ALOGE("Invalid threadCpuTimesMillis array length: %zu frequencies; expected: %zu",
- threadCpuTimesMillis.size(), frequencyCount);
+ ALOGE("Invalid array length: threadCpuTimesMillis");
return false;
}
-
if (selectedThreadCpuTimesMillis.size() != frequencyCount) {
- ALOGE("Invalid selectedThreadCpuTimesMillis array length: %zu frequencies; expected: %zu",
- selectedThreadCpuTimesMillis.size(), frequencyCount);
+ ALOGE("Invalid array length: selectedThreadCpuTimesMillisArray");
return false;
}
- for (size_t i = 0; i < frequencyCount; i++) {
- threadCpuTimesMillis[i] = 0;
- selectedThreadCpuTimesMillis[i] = 0;
- }
+ aggregateThreadCpuTimes(procPathStr, pid, threadIds, frequencyCount, selectedThreadIds.get(),
+ selectedThreadIds.size(),
+ reinterpret_cast<uint64_t *>(threadCpuTimesMillis.get()),
+ reinterpret_cast<uint64_t *>(selectedThreadCpuTimesMillis.get()));
- std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>> data =
- cpuTimeInStateReader->getAggregatedTaskCpuFreqTimes(pid,
- {DEFAULT_THREAD_AGGREGATION_KEY,
- SELECTED_THREAD_AGGREGATION_KEY});
- if (!data) {
- ALOGE("Cannot read thread CPU times for PID %d", pid);
- return false;
+ uint64_t processCpuTime;
+ bool ret = getProcessCpuTime(procPathStr, pid, processCpuTime);
+ if (ret) {
+ estimateProcessTimeInState(processCpuTime,
+ reinterpret_cast<uint64_t *>(threadCpuTimesMillis.get()),
+ frequencyCount,
+ reinterpret_cast<uint64_t *>(processCpuTimesMillis.get()));
}
-
- if (!flattenTimeInStateData(threadCpuTimesMillis, (*data)[DEFAULT_THREAD_AGGREGATION_KEY])) {
- return false;
- }
-
- if (!flattenTimeInStateData(selectedThreadCpuTimesMillis,
- (*data)[SELECTED_THREAD_AGGREGATION_KEY])) {
- return false;
- }
-
- // threadCpuTimesMillis returns CPU times for _all_ threads, including the selected ones
- for (size_t i = 0; i < frequencyCount; i++) {
- threadCpuTimesMillis[i] += selectedThreadCpuTimesMillis[i];
- }
-
- return true;
+ return ret;
}
static const JNINativeMethod g_single_methods[] = {
- {"getCpuFrequencyCount",
- "(Lcom/android/internal/os/KernelSingleProcessCpuThreadReader$CpuTimeInStateReader;)I",
- (void *)getCpuFrequencyCount},
- {"startTrackingProcessCpuTimes",
- "(ILcom/android/internal/os/KernelSingleProcessCpuThreadReader$CpuTimeInStateReader;)Z",
- (void *)startTrackingProcessCpuTimes},
- {"startAggregatingThreadCpuTimes",
- "([ILcom/android/internal/os/KernelSingleProcessCpuThreadReader$CpuTimeInStateReader;)Z",
- (void *)startAggregatingThreadCpuTimes},
- {"readProcessCpuUsage",
- "(I[J[J"
- "Lcom/android/internal/os/KernelSingleProcessCpuThreadReader$CpuTimeInStateReader;)Z",
- (void *)readProcessCpuUsage},
+ {"readProcessCpuUsage", "(Ljava/lang/String;I[I[J[J[J)Z", (void *)readProcessCpuUsage},
};
int register_com_android_internal_os_KernelSingleProcessCpuThreadReader(JNIEnv *env) {
@@ -257,77 +266,4 @@
g_single_methods, NELEM(g_single_methods));
}
-size_t MockCpuTimeInStateReader::getCpuFrequencyCount() {
- jclass cls = mEnv->GetObjectClass(mCpuTimeInStateReader);
- jmethodID mid = mEnv->GetMethodID(cls, "getCpuFrequencyCount", "()I");
- if (mid == 0) {
- ALOGE("Couldn't find the method getCpuFrequencyCount");
- return false;
- }
- return (size_t)mEnv->CallIntMethod(mCpuTimeInStateReader, mid);
-}
-
-bool MockCpuTimeInStateReader::startTrackingProcessCpuTimes(pid_t tgid) {
- jclass cls = mEnv->GetObjectClass(mCpuTimeInStateReader);
- jmethodID mid = mEnv->GetMethodID(cls, "startTrackingProcessCpuTimes", "(I)Z");
- if (mid == 0) {
- ALOGE("Couldn't find the method startTrackingProcessCpuTimes");
- return false;
- }
- return mEnv->CallBooleanMethod(mCpuTimeInStateReader, mid, tgid);
-}
-
-bool MockCpuTimeInStateReader::startAggregatingTaskCpuTimes(pid_t pid, uint16_t aggregationKey) {
- jclass cls = mEnv->GetObjectClass(mCpuTimeInStateReader);
- jmethodID mid = mEnv->GetMethodID(cls, "startAggregatingTaskCpuTimes", "(II)Z");
- if (mid == 0) {
- ALOGE("Couldn't find the method startAggregatingTaskCpuTimes");
- return false;
- }
- return mEnv->CallBooleanMethod(mCpuTimeInStateReader, mid, pid, aggregationKey);
-}
-
-std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>>
-MockCpuTimeInStateReader::getAggregatedTaskCpuFreqTimes(
- pid_t pid, const std::vector<uint16_t> &aggregationKeys) {
- jclass cls = mEnv->GetObjectClass(mCpuTimeInStateReader);
- jmethodID mid =
- mEnv->GetMethodID(cls, "getAggregatedTaskCpuFreqTimes", "(I)[Ljava/lang/String;");
- if (mid == 0) {
- ALOGE("Couldn't find the method getAggregatedTaskCpuFreqTimes");
- return {};
- }
-
- std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>> map;
-
- jobjectArray stringArray =
- (jobjectArray)mEnv->CallObjectMethod(mCpuTimeInStateReader, mid, pid);
- int size = mEnv->GetArrayLength(stringArray);
- for (int i = 0; i < size; i++) {
- ScopedUtfChars line(mEnv, (jstring)mEnv->GetObjectArrayElement(stringArray, i));
- uint16_t aggregationKey;
- std::vector<std::vector<uint64_t>> times;
-
- // Each string is formatted like this: "aggKey:t0_0 t0_1...:t1_0 t1_1..."
- auto fields = android::base::Split(line.c_str(), ":");
- android::base::ParseUint(fields[0], &aggregationKey);
-
- for (int j = 1; j < fields.size(); j++) {
- auto numbers = android::base::Split(fields[j], " ");
-
- std::vector<uint64_t> chunk;
- for (int k = 0; k < numbers.size(); k++) {
- uint64_t time;
- android::base::ParseUint(numbers[k], &time);
- chunk.emplace_back(time);
- }
- times.emplace_back(chunk);
- }
-
- map.emplace(aggregationKey, times);
- }
-
- return map;
-}
-
} // namespace android
diff --git a/core/res/Android.bp b/core/res/Android.bp
index f94a2b0..9ee5e5e1 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -19,6 +19,13 @@
sdk_version: "core_platform",
certificate: "platform",
+ // Disable dexpreopt and verify_uses_libraries check as the app
+ // contains no Java code to be dexpreopted.
+ enforce_uses_libs: false,
+ dex_preopt: {
+ enabled: false,
+ },
+
// Soong special-cases framework-res to install this alongside
// the libraries at /system/framework/framework-res.apk.
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 62a8ae5..28f5e35 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -393,6 +393,7 @@
<protected-broadcast android:name="android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST" />
<protected-broadcast android:name="android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION" />
<protected-broadcast android:name="android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW" />
+ <protected-broadcast android:name="android.net.wifi.action.REFRESH_USER_PROVISIONING" />
<protected-broadcast android:name="android.net.wifi.action.WIFI_NETWORK_SUGGESTION_POST_CONNECTION" />
<protected-broadcast android:name="android.net.wifi.action.WIFI_SCAN_AVAILABILITY_CHANGED" />
<protected-broadcast android:name="android.net.wifi.supplicant.CONNECTION_CHANGE" />
diff --git a/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java b/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java
new file mode 100644
index 0000000..b319886
--- /dev/null
+++ b/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.input;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.assertTrue;
+import static junit.framework.TestCase.fail;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.test.TestLooper;
+import android.platform.test.annotations.Presubmit;
+import android.view.InputDevice;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.internal.annotations.GuardedBy;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.junit.MockitoRule;
+
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests for {@link InputDeviceSensorManager}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksCoreTests:InputDeviceSensorManagerTest
+ */
+@Presubmit
+@RunWith(MockitoJUnitRunner.class)
+public class InputDeviceSensorManagerTest {
+ private static final String TAG = "InputDeviceSensorManagerTest";
+
+ private static final int DEVICE_ID = 1000;
+
+ @Rule public final MockitoRule mockito = MockitoJUnit.rule();
+
+ private TestLooper mTestLooper;
+ private ContextWrapper mContextSpy;
+ private InputManager mInputManager;
+ private InputDeviceSensorManager mSensorManager;
+ private IInputSensorEventListener mIInputSensorEventListener;
+ private final Object mLock = new Object();
+
+ @Mock private IInputManager mIInputManagerMock;
+
+ @Before
+ public void setUp() throws Exception {
+ mTestLooper = new TestLooper();
+ mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
+ InputManager inputManager = InputManager.resetInstance(mIInputManagerMock);
+
+ when(mContextSpy.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager);
+
+ when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{DEVICE_ID});
+
+ when(mIInputManagerMock.getInputDevice(eq(DEVICE_ID))).thenReturn(
+ createInputDeviceWithSensor(DEVICE_ID));
+
+ when(mIInputManagerMock.getSensorList(eq(DEVICE_ID))).thenReturn(new InputSensorInfo[] {
+ createInputSensorInfo(DEVICE_ID, Sensor.TYPE_ACCELEROMETER),
+ createInputSensorInfo(DEVICE_ID, Sensor.TYPE_GYROSCOPE)});
+
+ when(mIInputManagerMock.enableSensor(eq(DEVICE_ID), anyInt(), anyInt(), anyInt()))
+ .thenReturn(true);
+
+ when(mIInputManagerMock.registerSensorListener(any())).thenReturn(true);
+
+ mInputManager = mContextSpy.getSystemService(InputManager.class);
+ }
+
+ @After
+ public void tearDown() {
+ InputManager.clearInstance();
+ }
+
+ private class InputTestSensorEventListener implements SensorEventListener {
+ @GuardedBy("mLock")
+ private final BlockingQueue<SensorEvent> mEvents = new LinkedBlockingQueue<>();
+ InputTestSensorEventListener() {
+ super();
+ }
+
+ public SensorEvent waitForSensorEvent() {
+ try {
+ return mEvents.poll(5, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ fail("unexpectedly interrupted while waiting for SensorEvent");
+ return null;
+ }
+ }
+
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ synchronized (mLock) {
+ try {
+ mEvents.put(event);
+ } catch (InterruptedException ex) {
+ fail("interrupted while adding a SensorEvent to the queue");
+ }
+ }
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ }
+ }
+
+ private InputDevice createInputDeviceWithSensor(int id) {
+ InputDevice d = new InputDevice(id, 0 /* generation */, 0 /* controllerNumber */, "name",
+ 0 /* vendorId */, 0 /* productId */, "descriptor", true /* isExternal */,
+ 0 /* sources */, 0 /* keyboardType */, null /* keyCharacterMap */,
+ false /* hasVibrator */, false /* hasMicrophone */, false /* hasButtonUnderpad */,
+ true /* hasSensor */);
+ assertTrue(d.hasSensor());
+ return d;
+ }
+
+ private InputSensorInfo createInputSensorInfo(int id, int type) {
+ InputSensorInfo info = new InputSensorInfo("name", "vendor", 0 /* version */,
+ 0 /* handle */, type, 100.0f /*maxRange */, 0.02f /* resolution */,
+ 0.8f /* power */, 1000 /* minDelay */, 0 /* fifoReservedEventCount */,
+ 0 /* fifoMaxEventCount */, "" /* stringType */, "" /* requiredPermission */,
+ 0 /* maxDelay */, 0 /* flags */, id);
+ return info;
+ }
+
+ private InputDevice getSensorDevice(int[] deviceIds) {
+ for (int i = 0; i < deviceIds.length; i++) {
+ InputDevice device = mInputManager.getInputDevice(deviceIds[i]);
+ if (device.hasSensor()) {
+ return device;
+ }
+ }
+ return null;
+ }
+
+ @Test
+ public void getInputDeviceSensors_withExpectedType() throws Exception {
+ InputDevice device = getSensorDevice(mInputManager.getInputDeviceIds());
+ assertTrue(device != null);
+
+ SensorManager sensorManager = device.getSensorManager();
+ List<Sensor> accelList = sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
+ verify(mIInputManagerMock).getSensorList(eq(DEVICE_ID));
+ assertEquals(1, accelList.size());
+ assertEquals(DEVICE_ID, accelList.get(0).getId());
+ assertEquals(Sensor.TYPE_ACCELEROMETER, accelList.get(0).getType());
+
+ List<Sensor> gyroList = sensorManager.getSensorList(Sensor.TYPE_GYROSCOPE);
+ verify(mIInputManagerMock).getSensorList(eq(DEVICE_ID));
+ assertEquals(1, gyroList.size());
+ assertEquals(DEVICE_ID, gyroList.get(0).getId());
+ assertEquals(Sensor.TYPE_GYROSCOPE, gyroList.get(0).getType());
+
+ }
+
+ @Test
+ public void getInputDeviceSensors_withUnexpectedType() throws Exception {
+ InputDevice device = getSensorDevice(mInputManager.getInputDeviceIds());
+
+ assertTrue(device != null);
+ SensorManager sensorManager = device.getSensorManager();
+
+ List<Sensor> gameRotationList = sensorManager.getSensorList(
+ Sensor.TYPE_GAME_ROTATION_VECTOR);
+ verify(mIInputManagerMock).getSensorList(eq(DEVICE_ID));
+ assertEquals(0, gameRotationList.size());
+
+ List<Sensor> gravityList = sensorManager.getSensorList(Sensor.TYPE_GRAVITY);
+ verify(mIInputManagerMock).getSensorList(eq(DEVICE_ID));
+ assertEquals(0, gravityList.size());
+ }
+
+ @Test
+ public void testInputDeviceSensorListener() throws Exception {
+ InputDevice device = getSensorDevice(mInputManager.getInputDeviceIds());
+ assertTrue(device != null);
+
+ SensorManager sensorManager = device.getSensorManager();
+ Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+ assertEquals(Sensor.TYPE_ACCELEROMETER, sensor.getType());
+
+ doAnswer(invocation -> {
+ mIInputSensorEventListener = invocation.getArgument(0);
+ assertNotNull(mIInputSensorEventListener);
+ return true;
+ }).when(mIInputManagerMock).registerSensorListener(any());
+
+ InputTestSensorEventListener listener = new InputTestSensorEventListener();
+ assertTrue(sensorManager.registerListener(listener, sensor,
+ SensorManager.SENSOR_DELAY_NORMAL));
+ verify(mIInputManagerMock).registerSensorListener(any());
+ verify(mIInputManagerMock).enableSensor(eq(DEVICE_ID), eq(sensor.getType()),
+ anyInt(), anyInt());
+
+ float[] values = new float[] {0.12f, 9.8f, 0.2f};
+ mIInputSensorEventListener.onInputSensorChanged(DEVICE_ID, Sensor.TYPE_ACCELEROMETER,
+ SensorManager.SENSOR_STATUS_ACCURACY_HIGH, /* timestamp */ 0x1234abcd, values);
+
+ SensorEvent event = listener.waitForSensorEvent();
+ assertNotNull(event);
+ assertEquals(0x1234abcd, event.timestamp);
+ assertEquals(values.length, event.values.length);
+ for (int i = 0; i < values.length; i++) {
+ assertEquals(values[i], event.values[i], 0.001f);
+ }
+
+ sensorManager.unregisterListener(listener);
+ verify(mIInputManagerMock).disableSensor(eq(DEVICE_ID), eq(sensor.getType()));
+ }
+
+}
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index 5bce227c..1a86678 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -16,6 +16,7 @@
package android.os;
+import static android.os.FileUtils.convertToModernFd;
import static android.os.FileUtils.roundStorageSize;
import static android.os.FileUtils.translateModeAccessToPosix;
import static android.os.FileUtils.translateModePfdToPosix;
@@ -45,6 +46,8 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -67,6 +70,7 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Arrays;
@@ -562,6 +566,55 @@
assertEquals(O_RDWR, translateModeAccessToPosix(R_OK | W_OK | X_OK));
}
+ @Test
+ public void testConvertToModernFd() throws Exception {
+ final String nonce = String.valueOf(System.nanoTime());
+
+ final File cameraDir = new File("/storage/emulated/0/DCIM/Camera");
+ final File nonCameraDir = new File("/storage/emulated/0/Pictures");
+ cameraDir.mkdirs();
+ nonCameraDir.mkdirs();
+
+ final File validVideoCameraDir = new File(cameraDir, "validVideo-" + nonce + ".mp4");
+ final File validImageCameraDir = new File(cameraDir, "validImage-" + nonce + ".jpg");
+ final File invalidVideoCameraDir = new File(cameraDir, ".invalidVideo-" + nonce + ".mp4");
+
+ final File validVideoNonCameraDir = new File(nonCameraDir, "validVideo-" + nonce + ".mp4");
+ final File validImageNonCameraDir = new File(nonCameraDir, "validImage-" + nonce + ".jpg");
+
+ try {
+ FileDescriptor pfdValidVideoCameraDir =
+ ParcelFileDescriptor.open(validVideoCameraDir,
+ MODE_CREATE | MODE_READ_WRITE).getFileDescriptor();
+ FileDescriptor pfdValidImageCameraDir =
+ ParcelFileDescriptor.open(validImageCameraDir,
+ MODE_CREATE | MODE_READ_WRITE).getFileDescriptor();
+ FileDescriptor pfdInvalidVideoCameraDir =
+ ParcelFileDescriptor.open(invalidVideoCameraDir,
+ MODE_CREATE | MODE_READ_WRITE).getFileDescriptor();
+
+ FileDescriptor pfdValidVideoNonCameraDir =
+ ParcelFileDescriptor.open(validVideoNonCameraDir,
+ MODE_CREATE | MODE_READ_WRITE).getFileDescriptor();
+ FileDescriptor pfdValidImageNonCameraDir =
+ ParcelFileDescriptor.open(validImageNonCameraDir,
+ MODE_CREATE | MODE_READ_WRITE).getFileDescriptor();
+
+ assertNotNull(convertToModernFd(pfdValidVideoCameraDir));
+
+ assertNull(convertToModernFd(pfdValidImageCameraDir));
+ assertNull(convertToModernFd(pfdInvalidVideoCameraDir));
+ assertNull(convertToModernFd(pfdValidVideoNonCameraDir));
+ assertNull(convertToModernFd(pfdValidImageNonCameraDir));
+ } finally {
+ validVideoCameraDir.delete();
+ validImageCameraDir.delete();
+ invalidVideoCameraDir.delete();
+ validVideoNonCameraDir.delete();
+ validImageNonCameraDir.delete();
+ }
+ }
+
private static void assertTranslate(String string, int posix, int pfd) {
assertEquals(posix, translateModeStringToPosix(string));
assertEquals(string, translateModePosixToString(posix));
diff --git a/core/tests/coretests/src/android/util/BinaryXmlTest.java b/core/tests/coretests/src/android/util/BinaryXmlTest.java
index 6fa5a23..fd625dce 100644
--- a/core/tests/coretests/src/android/util/BinaryXmlTest.java
+++ b/core/tests/coretests/src/android/util/BinaryXmlTest.java
@@ -66,7 +66,7 @@
final TypedXmlPullParser in = Xml.newBinaryPullParser();
final ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
in.setInput(is, StandardCharsets.UTF_8.name());
- assertNext(in, START_TAG, "tag", 1);
+ assertNext(in, START_TAG, "tag");
assertEquals(count, in.getAttributeCount());
}
@@ -140,7 +140,12 @@
doVerifyWrite(xml);
data = os.toByteArray();
}
- try (InputStream is = new ByteArrayInputStream(data)) {
+ try (InputStream is = new ByteArrayInputStream(data) {
+ @Override
+ public boolean markSupported() {
+ return false;
+ }
+ }) {
doVerifyRead(Xml.resolvePullParser(is));
}
}
@@ -152,7 +157,12 @@
doVerifyWrite(xml);
data = os.toByteArray();
}
- try (InputStream is = new ByteArrayInputStream(data)) {
+ try (InputStream is = new ByteArrayInputStream(data) {
+ @Override
+ public boolean markSupported() {
+ return false;
+ }
+ }) {
doVerifyRead(Xml.resolvePullParser(is));
}
}
diff --git a/core/tests/coretests/src/android/util/XmlTest.java b/core/tests/coretests/src/android/util/XmlTest.java
index a8fc6f9..4e10ea9 100644
--- a/core/tests/coretests/src/android/util/XmlTest.java
+++ b/core/tests/coretests/src/android/util/XmlTest.java
@@ -53,6 +53,14 @@
}
@Test
+ public void testLargeValues_FastIndenting() throws Exception {
+ final TypedXmlSerializer out = Xml.newFastSerializer();
+ out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ doLargeValues(out,
+ Xml.newFastPullParser());
+ }
+
+ @Test
public void testLargeValues_Binary() throws Exception {
doLargeValues(Xml.newBinarySerializer(),
Xml.newBinaryPullParser());
@@ -81,7 +89,7 @@
final ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
in.setInput(is, StandardCharsets.UTF_8.name());
- assertNext(in, START_TAG, "tag", 1);
+ assertNext(in, START_TAG, "tag");
assertEquals(2, in.getAttributeCount());
assertEquals(string, in.getAttributeValue(null, "string"));
assertArrayEquals(bytes, in.getAttributeBytesBase64(null, "bytes"));
@@ -100,6 +108,14 @@
}
@Test
+ public void testPersistableBundle_FastIndenting() throws Exception {
+ final TypedXmlSerializer out = Xml.newFastSerializer();
+ out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ doPersistableBundle(out,
+ Xml.newFastPullParser());
+ }
+
+ @Test
public void testPersistableBundle_Binary() throws Exception {
doPersistableBundle(Xml.newBinarySerializer(),
Xml.newBinaryPullParser());
@@ -180,6 +196,14 @@
}
@Test
+ public void testVerify_FastIndenting() throws Exception {
+ final TypedXmlSerializer out = Xml.newFastSerializer();
+ out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ doVerify(out,
+ Xml.newFastPullParser());
+ }
+
+ @Test
public void testVerify_Binary() throws Exception {
doVerify(Xml.newBinarySerializer(),
Xml.newBinaryPullParser());
@@ -246,9 +270,12 @@
static void doVerifyRead(TypedXmlPullParser in) throws Exception {
assertEquals(START_DOCUMENT, in.getEventType());
- assertNext(in, START_TAG, "one", 1);
+ assertDepth(in, 0);
+ assertNext(in, START_TAG, "one");
+ assertDepth(in, 1);
{
- assertNext(in, START_TAG, "two", 2);
+ assertNext(in, START_TAG, "two");
+ assertDepth(in, 2);
{
assertEquals(14, in.getAttributeCount());
assertEquals(TEST_STRING,
@@ -285,27 +312,36 @@
assertEquals("49", in.getAttributeValue(null, "stringNumber"));
assertEquals(49, in.getAttributeInt(null, "stringNumber"));
}
- assertNext(in, END_TAG, "two", 2);
+ assertNext(in, END_TAG, "two");
+ assertDepth(in, 2);
- assertNext(in, START_TAG, "three", 2);
+ assertNext(in, START_TAG, "three");
+ assertDepth(in, 2);
{
- assertNext(in, TEXT);
+ assertNext(in, TEXT, null);
+ assertDepth(in, 2);
assertEquals("foo", in.getText().trim());
- assertNext(in, START_TAG, "four", 3);
+ assertNext(in, START_TAG, "four");
+ assertDepth(in, 3);
{
assertEquals(0, in.getAttributeCount());
}
- assertNext(in, END_TAG, "four", 3);
- assertNext(in, TEXT);
+ assertNext(in, END_TAG, "four");
+ assertDepth(in, 3);
+ assertNext(in, TEXT, null);
+ assertDepth(in, 2);
assertEquals("barbaz", in.getText().trim());
}
- assertNext(in, END_TAG, "three", 2);
+ assertNext(in, END_TAG, "three");
+ assertDepth(in, 2);
}
- assertNext(in, END_TAG, "one", 1);
- assertNext(in, END_DOCUMENT);
+ assertNext(in, END_TAG, "one");
+ assertDepth(in, 1);
+ assertNext(in, END_DOCUMENT, null);
+ assertDepth(in, 0);
}
- static void assertNext(TypedXmlPullParser in, int token) throws Exception {
+ static void assertNext(TypedXmlPullParser in, int token, String name) throws Exception {
// We're willing to skip over empty text regions, which some
// serializers emit transparently
int event;
@@ -313,12 +349,10 @@
}
assertEquals("next", token, event);
assertEquals("getEventType", token, in.getEventType());
+ assertEquals("getName", name, in.getName());
}
- static void assertNext(TypedXmlPullParser in, int token, String name, int depth)
- throws Exception {
- assertNext(in, token);
- assertEquals("getName", name, in.getName());
+ static void assertDepth(TypedXmlPullParser in, int depth) throws Exception {
assertEquals("getDepth", depth, in.getDepth());
}
}
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
index 7e1e7f4..ab24f89 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
@@ -33,6 +33,9 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import java.util.Arrays;
+import java.util.List;
+
/**
* Tests for AccessibilityInteractionClient
*/
@@ -62,7 +65,7 @@
final long accessibilityNodeId = 0x4321L;
AccessibilityNodeInfo nodeFromConnection = AccessibilityNodeInfo.obtain();
nodeFromConnection.setSourceNodeId(accessibilityNodeId, windowId);
- mMockConnection.mInfoToReturn = nodeFromConnection;
+ mMockConnection.mInfosToReturn = Arrays.asList(nodeFromConnection);
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
AccessibilityNodeInfo node = client.findAccessibilityNodeInfoByAccessibilityId(
MOCK_CONNECTION_ID, windowId, accessibilityNodeId, true, 0, null);
@@ -72,7 +75,7 @@
}
private static class MockConnection extends AccessibilityServiceConnectionImpl {
- AccessibilityNodeInfo mInfoToReturn;
+ List<AccessibilityNodeInfo> mInfosToReturn;
@Override
public String[] findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
@@ -80,7 +83,7 @@
IAccessibilityInteractionConnectionCallback callback, int flags, long threadId,
Bundle arguments) {
try {
- callback.setFindAccessibilityNodeInfoResult(mInfoToReturn, interactionId);
+ callback.setFindAccessibilityNodeInfosResult(mInfosToReturn, interactionId);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java
index 40ecf9a..66fdfff 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -16,6 +16,9 @@
package android.widget;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
@@ -30,6 +33,7 @@
import android.text.Layout;
import android.text.PrecomputedText;
import android.view.View;
+import android.view.inputmethod.EditorInfo;
import android.widget.TextView.BufferType;
import androidx.test.InstrumentationRegistry;
@@ -254,6 +258,24 @@
assertEquals("", mTextView.getTransformed().toString());
}
+ @Test
+ @UiThreadTest
+ public void testPortraitDoesntSupportFullscreenIme() {
+ mActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
+ mTextView = new NullSetTextTextView(mActivity);
+ mTextView.requestFocus();
+ assertEquals("IME_FLAG_NO_FULLSCREEN should be set",
+ mTextView.getImeOptions(),
+ mTextView.getImeOptions() & EditorInfo.IME_FLAG_NO_FULLSCREEN);
+
+ mTextView.clearFocus();
+ mActivity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+ mTextView = new NullSetTextTextView(mActivity);
+ mTextView.requestFocus();
+ assertEquals("IME_FLAG_NO_FULLSCREEN should not be set",
+ 0, mTextView.getImeOptions() & EditorInfo.IME_FLAG_NO_FULLSCREEN);
+ }
+
private String createLongText() {
int size = 600 * 1000;
final StringBuilder builder = new StringBuilder(size);
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index cfa8c4d..bd41542 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -38,7 +38,9 @@
BatteryStatsTimeBaseTest.class,
BatteryStatsTimerTest.class,
BatteryStatsUidTest.class,
+ BatteryUsageStatsTest.class,
BatteryStatsUserLifecycleTests.class,
+ BluetoothPowerCalculatorTest.class,
BstatsCpuTimesValidationTest.class,
KernelCpuProcStringReaderTest.class,
KernelCpuUidActiveTimeReaderTest.class,
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
new file mode 100644
index 0000000..96e9c4a
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+
+import android.os.BatteryConsumer;
+import android.os.BatteryUsageStats;
+import android.os.Parcel;
+import android.os.SystemBatteryConsumer;
+import android.os.UidBatteryConsumer;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BatteryUsageStatsTest {
+
+ @Test
+ public void testBuilder() {
+ BatteryUsageStats batteryUsageStats = buildBatteryUsageStats();
+ validateBatteryUsageStats(batteryUsageStats);
+ }
+
+ @Test
+ public void testParcelability() {
+ final BatteryUsageStats outBatteryUsageStats = buildBatteryUsageStats();
+ final Parcel outParcel = Parcel.obtain();
+ outParcel.writeParcelable(outBatteryUsageStats, 0);
+ final byte[] bytes = outParcel.marshall();
+ outParcel.recycle();
+
+ final Parcel inParcel = Parcel.obtain();
+ inParcel.unmarshall(bytes, 0, bytes.length);
+ inParcel.setDataPosition(0);
+ final BatteryUsageStats inBatteryUsageStats =
+ inParcel.readParcelable(getClass().getClassLoader());
+ assertThat(inBatteryUsageStats).isNotNull();
+ validateBatteryUsageStats(inBatteryUsageStats);
+ }
+
+ private BatteryUsageStats buildBatteryUsageStats() {
+ final MockClocks clocks = new MockClocks();
+ final MockBatteryStatsImpl batteryStats = new MockBatteryStatsImpl(clocks);
+ final BatteryStatsImpl.Uid batteryStatsUid = batteryStats.getUidStatsLocked(2000);
+
+ final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(1, 1, true);
+ builder.setConsumedPower(100);
+ builder.setDischargePercentage(20);
+
+ final UidBatteryConsumer.Builder uidBatteryConsumerBuilder =
+ builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid);
+ uidBatteryConsumerBuilder.setPackageWithHighestDrain("foo");
+ uidBatteryConsumerBuilder.setConsumedPower(200);
+ uidBatteryConsumerBuilder.setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, 300);
+ uidBatteryConsumerBuilder.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, 400);
+ uidBatteryConsumerBuilder.setConsumedPowerForCustomComponent(
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 500);
+ uidBatteryConsumerBuilder.setConsumedPowerForCustomComponent(
+ BatteryConsumer.FIRST_MODELED_POWER_COMPONENT_ID
+ + BatteryConsumer.POWER_COMPONENT_CPU, 510);
+ uidBatteryConsumerBuilder.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU, 600);
+ uidBatteryConsumerBuilder.setUsageDurationMillis(
+ BatteryConsumer.TIME_COMPONENT_CPU_FOREGROUND, 700);
+ uidBatteryConsumerBuilder.setUsageDurationForCustomComponentMillis(
+ BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID, 800);
+
+ final SystemBatteryConsumer.Builder systemBatteryConsumerBuilder =
+ builder.getOrCreateSystemBatteryConsumerBuilder(
+ SystemBatteryConsumer.DRAIN_TYPE_CAMERA);
+ systemBatteryConsumerBuilder.setConsumedPower(10000);
+ systemBatteryConsumerBuilder.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, 10100);
+ systemBatteryConsumerBuilder.setConsumedPowerForCustomComponent(
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10200);
+ systemBatteryConsumerBuilder.setConsumedPowerForCustomComponent(
+ BatteryConsumer.FIRST_MODELED_POWER_COMPONENT_ID
+ + BatteryConsumer.POWER_COMPONENT_CPU, 10210);
+ systemBatteryConsumerBuilder.setUsageDurationMillis(
+ BatteryConsumer.TIME_COMPONENT_CPU, 10300);
+ systemBatteryConsumerBuilder.setUsageDurationForCustomComponentMillis(
+ BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID, 10400);
+
+ return builder.build();
+ }
+
+ public void validateBatteryUsageStats(BatteryUsageStats batteryUsageStats) {
+ assertThat(batteryUsageStats.getConsumedPower()).isEqualTo(100);
+ assertThat(batteryUsageStats.getDischargePercentage()).isEqualTo(20);
+
+ final List<UidBatteryConsumer> uidBatteryConsumers =
+ batteryUsageStats.getUidBatteryConsumers();
+ for (UidBatteryConsumer uidBatteryConsumer : uidBatteryConsumers) {
+ if (uidBatteryConsumer.getUid() == 2000) {
+ assertThat(uidBatteryConsumer.getPackageWithHighestDrain()).isEqualTo("foo");
+ assertThat(uidBatteryConsumer.getConsumedPower()).isEqualTo(200);
+ assertThat(uidBatteryConsumer.getConsumedPower(
+ BatteryConsumer.POWER_COMPONENT_USAGE)).isEqualTo(300);
+ assertThat(uidBatteryConsumer.getConsumedPower(
+ BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(400);
+ assertThat(uidBatteryConsumer.getConsumedPowerForCustomComponent(
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(500);
+ assertThat(uidBatteryConsumer.getConsumedPowerForCustomComponent(
+ BatteryConsumer.FIRST_MODELED_POWER_COMPONENT_ID
+ + BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(510);
+ assertThat(uidBatteryConsumer.getUsageDurationMillis(
+ BatteryConsumer.TIME_COMPONENT_CPU)).isEqualTo(600);
+ assertThat(uidBatteryConsumer.getUsageDurationMillis(
+ BatteryConsumer.TIME_COMPONENT_CPU_FOREGROUND)).isEqualTo(700);
+ assertThat(uidBatteryConsumer.getUsageDurationForCustomComponentMillis(
+ BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID)).isEqualTo(800);
+ } else {
+ fail("Unexpected UID " + uidBatteryConsumer.getUid());
+ }
+ }
+
+ final List<SystemBatteryConsumer> systemBatteryConsumers =
+ batteryUsageStats.getSystemBatteryConsumers();
+ for (SystemBatteryConsumer systemBatteryConsumer : systemBatteryConsumers) {
+ if (systemBatteryConsumer.getDrainType() == SystemBatteryConsumer.DRAIN_TYPE_CAMERA) {
+ assertThat(systemBatteryConsumer.getConsumedPower()).isEqualTo(10000);
+ assertThat(systemBatteryConsumer.getConsumedPower(
+ BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(10100);
+ assertThat(systemBatteryConsumer.getConsumedPowerForCustomComponent(
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(10200);
+ assertThat(systemBatteryConsumer.getConsumedPowerForCustomComponent(
+ BatteryConsumer.FIRST_MODELED_POWER_COMPONENT_ID
+ + BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(10210);
+ assertThat(systemBatteryConsumer.getUsageDurationMillis(
+ BatteryConsumer.TIME_COMPONENT_CPU)).isEqualTo(10300);
+ assertThat(systemBatteryConsumer.getUsageDurationForCustomComponentMillis(
+ BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID)).isEqualTo(10400);
+ } else {
+ fail("Unexpected drain type " + systemBatteryConsumer.getDrainType());
+ }
+ }
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
new file mode 100644
index 0000000..96eb8da
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.annotation.Nullable;
+import android.os.BatteryConsumer;
+import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
+import android.os.Process;
+import android.os.SystemBatteryConsumer;
+import android.os.UidBatteryConsumer;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class BluetoothPowerCalculatorTest {
+ private static final double PRECISION = 0.00001;
+ private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
+
+ @Mock
+ private PowerProfile mMockPowerProfile;
+ private MockBatteryStatsImpl mMockBatteryStats;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mMockBatteryStats = new MockBatteryStatsImpl(new MockClocks()) {
+ @Override
+ public boolean hasBluetoothActivityReporting() {
+ return true;
+ }
+ };
+ mMockBatteryStats.getOnBatteryTimeBase().setRunning(true, 100_000, 100_000);
+ when(mMockPowerProfile.getAveragePower(
+ PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE)).thenReturn(10.0);
+ when(mMockPowerProfile.getAveragePower(
+ PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX)).thenReturn(50.0);
+ when(mMockPowerProfile.getAveragePower(
+ PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX)).thenReturn(100.0);
+ }
+
+ @Test
+ public void testTimerBasedModel() {
+ setDurationsAndPower(
+ mMockBatteryStats.getUidStatsLocked(Process.BLUETOOTH_UID)
+ .getOrCreateBluetoothControllerActivityLocked(),
+ 1000, 2000, 3000, 0);
+
+ setDurationsAndPower(mMockBatteryStats.getUidStatsLocked(APP_UID)
+ .getOrCreateBluetoothControllerActivityLocked(),
+ 4000, 5000, 6000, 0);
+
+ setDurationsAndPower((BatteryStatsImpl.ControllerActivityCounterImpl)
+ mMockBatteryStats.getBluetoothControllerActivity(),
+ 6000, 8000, 10000, 0);
+
+ BatteryUsageStats batteryUsageStats = buildBatteryUsageStats();
+
+ assertBluetoothPowerAndDuration(
+ getUidBatteryConsumer(batteryUsageStats, Process.BLUETOOTH_UID),
+ 0.11388, 6000);
+ assertBluetoothPowerAndDuration(
+ getUidBatteryConsumer(batteryUsageStats, APP_UID),
+ 0.24722, 15000);
+ assertBluetoothPowerAndDuration(
+ getBluetoothSystemBatteryConsumer(batteryUsageStats,
+ SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH),
+ 0.15833, 9000);
+ }
+
+ @Test
+ public void testReportedPowerBasedModel() {
+ setDurationsAndPower(
+ mMockBatteryStats.getUidStatsLocked(Process.BLUETOOTH_UID)
+ .getOrCreateBluetoothControllerActivityLocked(),
+ 1000, 2000, 3000, 360000);
+
+ setDurationsAndPower(mMockBatteryStats.getUidStatsLocked(APP_UID)
+ .getOrCreateBluetoothControllerActivityLocked(),
+ 4000, 5000, 6000, 720000);
+
+ setDurationsAndPower((BatteryStatsImpl.ControllerActivityCounterImpl)
+ mMockBatteryStats.getBluetoothControllerActivity(),
+ 6000, 8000, 10000, 1260000);
+
+ BatteryUsageStats batteryUsageStats = buildBatteryUsageStats();
+
+ assertBluetoothPowerAndDuration(
+ getUidBatteryConsumer(batteryUsageStats, Process.BLUETOOTH_UID),
+ 0.1, 6000);
+ assertBluetoothPowerAndDuration(
+ getUidBatteryConsumer(batteryUsageStats, APP_UID),
+ 0.2, 15000);
+ assertBluetoothPowerAndDuration(
+ getBluetoothSystemBatteryConsumer(batteryUsageStats,
+ SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH),
+ 0.15, 9000);
+ }
+
+ private void setDurationsAndPower(
+ BatteryStatsImpl.ControllerActivityCounterImpl controllerActivity, int idleDurationMs,
+ int rxDurationMs, int txDurationMs, long powerMaMs) {
+ controllerActivity.getIdleTimeCounter().addCountLocked(idleDurationMs);
+ controllerActivity.getRxTimeCounter().addCountLocked(rxDurationMs);
+ controllerActivity.getTxTimeCounters()[0].addCountLocked(txDurationMs);
+ controllerActivity.getPowerCounter().addCountLocked(powerMaMs);
+ }
+
+ private BatteryUsageStats buildBatteryUsageStats() {
+ BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(0, 0, false);
+ builder.getOrCreateUidBatteryConsumerBuilder(
+ mMockBatteryStats.getUidStatsLocked(Process.BLUETOOTH_UID));
+ builder.getOrCreateUidBatteryConsumerBuilder(
+ mMockBatteryStats.getUidStatsLocked(APP_UID));
+
+ BluetoothPowerCalculator bpc = new BluetoothPowerCalculator(mMockPowerProfile);
+ bpc.calculate(builder, mMockBatteryStats, 200_000, 200_000, BatteryUsageStatsQuery.DEFAULT,
+ null);
+ return builder.build();
+ }
+
+ private UidBatteryConsumer getUidBatteryConsumer(BatteryUsageStats batteryUsageStats, int uid) {
+ for (UidBatteryConsumer ubc : batteryUsageStats.getUidBatteryConsumers()) {
+ if (ubc.getUid() == uid) {
+ return ubc;
+ }
+ }
+ return null;
+ }
+
+ private SystemBatteryConsumer getBluetoothSystemBatteryConsumer(
+ BatteryUsageStats batteryUsageStats, int drainType) {
+ for (SystemBatteryConsumer sbc : batteryUsageStats.getSystemBatteryConsumers()) {
+ if (sbc.getDrainType() == drainType) {
+ return sbc;
+ }
+ }
+ return null;
+ }
+
+ private void assertBluetoothPowerAndDuration(@Nullable BatteryConsumer batteryConsumer,
+ double powerMah, int durationMs) {
+ assertThat(batteryConsumer).isNotNull();
+
+ double consumedPower = batteryConsumer.getConsumedPower(
+ BatteryConsumer.POWER_COMPONENT_BLUETOOTH);
+ assertThat(consumedPower).isWithin(PRECISION).of(powerMah);
+
+ long usageDurationMillis = batteryConsumer.getUsageDurationMillis(
+ BatteryConsumer.TIME_COMPONENT_BLUETOOTH);
+
+ assertThat(usageDurationMillis).isEqualTo(durationMs);
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java
index 2de800b..b5720a2 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java
@@ -19,87 +19,122 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.os.FileUtils;
+
+import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.File;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class KernelSingleProcessCpuThreadReaderTest {
+ private File mProcDirectory;
+
+ @Before
+ public void setUp() {
+ Context context = InstrumentationRegistry.getContext();
+ mProcDirectory = context.getDir("proc", Context.MODE_PRIVATE);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ FileUtils.deleteContents(mProcDirectory);
+ }
+
@Test
public void getProcessCpuUsage() throws IOException {
- // Units are nanoseconds
- MockCpuTimeInStateReader mockReader = new MockCpuTimeInStateReader(4, new String[] {
- "0:1000000000 2000000000 3000000000:4000000000",
- "1:100000000 200000000 300000000:400000000",
- });
+ setupDirectory(42,
+ new int[] {42, 1, 2, 3},
+ new int[] {1000, 2000},
+ // Units are 10ms aka 10000Us
+ new int[][] {{100, 200}, {0, 200}, {100, 300}, {0, 600}},
+ new int[] {4500, 500});
KernelSingleProcessCpuThreadReader reader = new KernelSingleProcessCpuThreadReader(42,
- mockReader);
- reader.setSelectedThreadIds(new int[] {2, 3});
- reader.startTrackingThreadCpuTimes();
+ mProcDirectory.toPath());
KernelSingleProcessCpuThreadReader.ProcessCpuUsage processCpuUsage =
- reader.getProcessCpuUsage();
- assertThat(mockReader.mTrackedTgid).isEqualTo(42);
- // The strings are formatted as <TID TGID AGG_KEY>, where AGG_KEY is 1 for binder
- // threads and 0 for all other threads.
- assertThat(mockReader.mTrackedTasks).containsExactly(
- "2 1",
- "3 1");
- assertThat(processCpuUsage.threadCpuTimesMillis).isEqualTo(
- new long[] {1100, 2200, 3300, 4400});
- assertThat(processCpuUsage.selectedThreadCpuTimesMillis).isEqualTo(
- new long[] {100, 200, 300, 400});
+ reader.getProcessCpuUsage(new int[] {2, 3});
+ assertThat(processCpuUsage.threadCpuTimesMillis).isEqualTo(new long[] {2000, 13000});
+ assertThat(processCpuUsage.selectedThreadCpuTimesMillis).isEqualTo(new long[] {1000, 9000});
+ assertThat(processCpuUsage.processCpuTimesMillis).isEqualTo(new long[] {6666, 43333});
}
@Test
public void getCpuFrequencyCount() throws IOException {
- MockCpuTimeInStateReader mockReader = new MockCpuTimeInStateReader(3, new String[0]);
+ setupDirectory(13,
+ new int[] {13},
+ new int[] {1000, 2000, 3000},
+ new int[][] {{100, 200, 300}},
+ new int[] {14, 15});
KernelSingleProcessCpuThreadReader reader = new KernelSingleProcessCpuThreadReader(13,
- mockReader);
+ mProcDirectory.toPath());
int cpuFrequencyCount = reader.getCpuFrequencyCount();
assertThat(cpuFrequencyCount).isEqualTo(3);
}
- public static class MockCpuTimeInStateReader implements
- KernelSingleProcessCpuThreadReader.CpuTimeInStateReader {
- private final int mCpuFrequencyCount;
- private final String[] mAggregatedTaskCpuFreqTimes;
- public int mTrackedTgid;
- public List<String> mTrackedTasks = new ArrayList<>();
+ private void setupDirectory(int pid, int[] threadIds, int[] cpuFrequencies,
+ int[][] threadCpuTimes, int[] processCpuTimes)
+ throws IOException {
- public MockCpuTimeInStateReader(int cpuFrequencyCount,
- String[] aggregatedTaskCpuFreqTimes) {
- mCpuFrequencyCount = cpuFrequencyCount;
- mAggregatedTaskCpuFreqTimes = aggregatedTaskCpuFreqTimes;
+ assertTrue(mProcDirectory.toPath().resolve("self").toFile().mkdirs());
+
+ try (OutputStream timeInStateStream =
+ Files.newOutputStream(
+ mProcDirectory.toPath().resolve("self").resolve("time_in_state"))) {
+ for (int i = 0; i < cpuFrequencies.length; i++) {
+ final String line = cpuFrequencies[i] + " 0\n";
+ timeInStateStream.write(line.getBytes());
+ }
}
- @Override
- public int getCpuFrequencyCount() {
- return mCpuFrequencyCount;
+ Path processPath = mProcDirectory.toPath().resolve(String.valueOf(pid));
+
+ // Make /proc/$PID
+ assertTrue(processPath.toFile().mkdirs());
+
+ // Write /proc/$PID/stat. Only the fields 14-17 matter.
+ try (OutputStream timeInStateStream = Files.newOutputStream(processPath.resolve("stat"))) {
+ timeInStateStream.write(
+ (pid + " (test) S 4 5 6 7 8 9 10 11 12 13 "
+ + processCpuTimes[0] + " "
+ + processCpuTimes[1] + " "
+ + "16 17 18 19 20 ...").getBytes());
}
- @Override
- public boolean startTrackingProcessCpuTimes(int tgid) {
- mTrackedTgid = tgid;
- return true;
- }
+ // Make /proc/$PID/task
+ final Path selfThreadsPath = processPath.resolve("task");
+ assertTrue(selfThreadsPath.toFile().mkdirs());
- public boolean startAggregatingTaskCpuTimes(int pid, int aggregationKey) {
- mTrackedTasks.add(pid + " " + aggregationKey);
- return true;
- }
+ // Make thread directories
+ for (int i = 0; i < threadIds.length; i++) {
+ // Make /proc/$PID/task/$TID
+ final Path threadPath = selfThreadsPath.resolve(String.valueOf(threadIds[i]));
+ assertTrue(threadPath.toFile().mkdirs());
- public String[] getAggregatedTaskCpuFreqTimes(int pid) {
- return mAggregatedTaskCpuFreqTimes;
+ // Make /proc/$PID/task/$TID/time_in_state
+ try (OutputStream timeInStateStream =
+ Files.newOutputStream(threadPath.resolve("time_in_state"))) {
+ for (int j = 0; j < cpuFrequencies.length; j++) {
+ final String line = cpuFrequencies[j] + " " + threadCpuTimes[i][j] + "\n";
+ timeInStateStream.write(line.getBytes());
+ }
+ }
}
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index 1b1590a..c775137 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -47,6 +47,7 @@
mScreenDozeTimer = new BatteryStatsImpl.StopwatchTimer(clocks, null, -1, null,
mOnBatteryTimeBase);
mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
+ mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase, 1);
setExternalStatsSyncLocked(new DummyExternalStatsSync());
for (int i = 0; i < GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS; i++) {
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java
index d116d4d..121c637 100644
--- a/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java
@@ -16,86 +16,146 @@
package com.android.internal.os;
-import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertTrue;
+import android.content.Context;
+import android.os.FileUtils;
+
+import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.File;
import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class SystemServerCpuThreadReaderTest {
+ private File mProcDirectory;
+
+ @Before
+ public void setUp() {
+ Context context = InstrumentationRegistry.getContext();
+ mProcDirectory = context.getDir("proc", Context.MODE_PRIVATE);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ FileUtils.deleteContents(mProcDirectory);
+ }
@Test
- public void testReadDelta() throws IOException {
+ public void testReaderDelta_firstTime() throws IOException {
int pid = 42;
+ setupDirectory(
+ pid,
+ new int[] {42, 1, 2, 3},
+ new int[] {1000, 2000},
+ // Units are 10ms aka 10000Us
+ new int[][] {{100, 200}, {0, 200}, {0, 300}, {0, 400}},
+ new int[] {1400, 1500});
- MockCpuTimeInStateReader mockReader = new MockCpuTimeInStateReader(4);
- // Units are nanoseconds
- mockReader.setAggregatedTaskCpuFreqTimes(new String[] {
- "0:1000000000 2000000000 3000000000:4000000000",
- "1:100000000 200000000 300000000:400000000",
- });
+ SystemServerCpuThreadReader reader = new SystemServerCpuThreadReader(
+ mProcDirectory.toPath(), pid);
+ reader.setBinderThreadNativeTids(new int[] {1, 3});
+ SystemServerCpuThreadReader.SystemServiceCpuThreadTimes systemServiceCpuThreadTimes =
+ reader.readDelta();
+ assertArrayEquals(new long[] {100 * 10000, 1100 * 10000},
+ systemServiceCpuThreadTimes.threadCpuTimesUs);
+ assertArrayEquals(new long[] {0, 600 * 10000},
+ systemServiceCpuThreadTimes.binderThreadCpuTimesUs);
+ }
- SystemServerCpuThreadReader reader = new SystemServerCpuThreadReader(pid, mockReader);
+ @Test
+ public void testReaderDelta_nextTime() throws IOException {
+ int pid = 42;
+ setupDirectory(
+ pid,
+ new int[] {42, 1, 2, 3},
+ new int[] {1000, 2000},
+ new int[][] {{100, 200}, {0, 200}, {0, 300}, {0, 400}},
+ new int[] {1400, 1500});
+
+ SystemServerCpuThreadReader reader = new SystemServerCpuThreadReader(
+ mProcDirectory.toPath(), pid);
reader.setBinderThreadNativeTids(new int[] {1, 3});
- // The first invocation of readDelta populates the "last" snapshot
+ // First time, populate "last" snapshot
+ reader.readDelta();
+
+ FileUtils.deleteContents(mProcDirectory);
+ setupDirectory(
+ pid,
+ new int[] {42, 1, 2, 3},
+ new int[] {1000, 2000},
+ new int[][] {{500, 600}, {700, 800}, {900, 1000}, {1100, 1200}},
+ new int[] {2400, 2500});
+
+ // Second time, get the actual delta
SystemServerCpuThreadReader.SystemServiceCpuThreadTimes systemServiceCpuThreadTimes =
reader.readDelta();
- assertThat(systemServiceCpuThreadTimes.threadCpuTimesUs)
- .isEqualTo(new long[] {1100000, 2200000, 3300000, 4400000});
- assertThat(systemServiceCpuThreadTimes.binderThreadCpuTimesUs)
- .isEqualTo(new long[] {100000, 200000, 300000, 400000});
-
- mockReader.setAggregatedTaskCpuFreqTimes(new String[] {
- "0:1010000000 2020000000 3030000000:4040000000",
- "1:101000000 202000000 303000000:404000000",
- });
-
- // The second invocation gets the actual delta
- systemServiceCpuThreadTimes = reader.readDelta();
-
- assertThat(systemServiceCpuThreadTimes.threadCpuTimesUs)
- .isEqualTo(new long[] {11000, 22000, 33000, 44000});
- assertThat(systemServiceCpuThreadTimes.binderThreadCpuTimesUs)
- .isEqualTo(new long[] {1000, 2000, 3000, 4000});
+ assertArrayEquals(new long[] {3100 * 10000, 2500 * 10000},
+ systemServiceCpuThreadTimes.threadCpuTimesUs);
+ assertArrayEquals(new long[] {1800 * 10000, 1400 * 10000},
+ systemServiceCpuThreadTimes.binderThreadCpuTimesUs);
}
- public static class MockCpuTimeInStateReader implements
- KernelSingleProcessCpuThreadReader.CpuTimeInStateReader {
- private final int mCpuFrequencyCount;
- private String[] mAggregatedTaskCpuFreqTimes;
+ private void setupDirectory(int pid, int[] threadIds, int[] cpuFrequencies, int[][] cpuTimes,
+ int[] processCpuTimes)
+ throws IOException {
- MockCpuTimeInStateReader(int frequencyCount) {
- mCpuFrequencyCount = frequencyCount;
+ assertTrue(mProcDirectory.toPath().resolve("self").toFile().mkdirs());
+
+ try (OutputStream timeInStateStream =
+ Files.newOutputStream(
+ mProcDirectory.toPath().resolve("self").resolve("time_in_state"))) {
+ for (int i = 0; i < cpuFrequencies.length; i++) {
+ final String line = cpuFrequencies[i] + " 0\n";
+ timeInStateStream.write(line.getBytes());
+ }
}
- @Override
- public int getCpuFrequencyCount() {
- return mCpuFrequencyCount;
+ Path processPath = mProcDirectory.toPath().resolve(String.valueOf(pid));
+ // Make /proc/$PID
+ assertTrue(processPath.toFile().mkdirs());
+
+ // Write /proc/$PID/stat. Only the fields 14-17 matter.
+ try (OutputStream timeInStateStream = Files.newOutputStream(processPath.resolve("stat"))) {
+ timeInStateStream.write(
+ (pid + " (test) S 4 5 6 7 8 9 10 11 12 13 "
+ + processCpuTimes[0] + " "
+ + processCpuTimes[1] + " "
+ + "16 17 18 19 20 ...").getBytes());
}
- @Override
- public boolean startTrackingProcessCpuTimes(int tgid) {
- return true;
- }
+ // Make /proc/$PID/task
+ final Path selfThreadsPath = processPath.resolve("task");
+ assertTrue(selfThreadsPath.toFile().mkdirs());
- public boolean startAggregatingTaskCpuTimes(int pid, int aggregationKey) {
- return true;
- }
+ // Make thread directories
+ for (int i = 0; i < threadIds.length; i++) {
+ // Make /proc/$PID/task/$TID
+ final Path threadPath = selfThreadsPath.resolve(String.valueOf(threadIds[i]));
+ assertTrue(threadPath.toFile().mkdirs());
- public void setAggregatedTaskCpuFreqTimes(String[] mAggregatedTaskCpuFreqTimes) {
- this.mAggregatedTaskCpuFreqTimes = mAggregatedTaskCpuFreqTimes;
- }
-
- public String[] getAggregatedTaskCpuFreqTimes(int pid) {
- return mAggregatedTaskCpuFreqTimes;
+ // Make /proc/$PID/task/$TID/time_in_state
+ try (OutputStream timeInStateStream =
+ Files.newOutputStream(threadPath.resolve("time_in_state"))) {
+ for (int j = 0; j < cpuFrequencies.length; j++) {
+ final String line = cpuFrequencies[j] + " " + cpuTimes[i][j] + "\n";
+ timeInStateStream.write(line.getBytes());
+ }
+ }
}
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
index c8e8585..dbb36fb 100644
--- a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
@@ -66,6 +66,7 @@
public void testCalculateApp() {
// Test Power Profile has two CPU clusters with 3 and 4 speeds, thus 7 freq times total
mMockSystemServerCpuThreadReader.setCpuTimes(
+ new long[] {10000, 15000, 20000, 25000, 30000, 35000, 40000},
new long[] {30000, 40000, 50000, 60000, 70000, 80000, 90000},
new long[] {20000, 30000, 40000, 50000, 60000, 70000, 80000});
@@ -145,7 +146,9 @@
super(null);
}
- public void setCpuTimes(long[] threadCpuTimesUs, long[] binderThreadCpuTimesUs) {
+ public void setCpuTimes(long[] processCpuTimesUs, long[] threadCpuTimesUs,
+ long[] binderThreadCpuTimesUs) {
+ mThreadTimes.processCpuTimesUs = processCpuTimesUs;
mThreadTimes.threadCpuTimesUs = threadCpuTimesUs;
mThreadTimes.binderThreadCpuTimesUs = binderThreadCpuTimesUs;
}
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
index 306388f..9531181d 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
@@ -195,6 +195,11 @@
}
@Override
+ public boolean shouldHandleTvPowerKey() {
+ return false;
+ }
+
+ @Override
public void queryDisplayStatus(final IHdmiControlCallback callback) {
}
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index d8a735c..faf4973 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -901,6 +901,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1069336896": {
+ "message": "onRootTaskOrderChanged(): rootTask=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+ "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+ },
"-1066383762": {
"message": "Sleep still waiting to pause %s",
"level": "VERBOSE",
@@ -1303,6 +1309,12 @@
"group": "WM_DEBUG_CONFIGURATION",
"at": "com\/android\/server\/am\/ActivityManagerService.java"
},
+ "-592371899": {
+ "message": "Skipping rootTask: (mismatch activity\/rootTask) %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
+ },
"-583031528": {
"message": "%s",
"level": "INFO",
@@ -2119,12 +2131,6 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/AppTransition.java"
},
- "349443311": {
- "message": "pauseBackStacks: task=%s mResumedActivity=%s",
- "level": "DEBUG",
- "group": "WM_DEBUG_STATES",
- "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
- },
"355720268": {
"message": "stopFreezingDisplayLocked: Unfreezing now",
"level": "DEBUG",
@@ -2161,6 +2167,12 @@
"group": "WM_DEBUG_BOOT",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "391189028": {
+ "message": "pauseBackTasks: task=%s mResumedActivity=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
+ },
"397105698": {
"message": "grantEmbeddedWindowFocus remove request for win=%s dropped since no candidate was found",
"level": "VERBOSE",
@@ -2245,12 +2257,6 @@
"group": "WM_DEBUG_WINDOW_ORGANIZER",
"at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
},
- "490877640": {
- "message": "onStackOrderChanged(): stack=%s",
- "level": "DEBUG",
- "group": "WM_DEBUG_RECENTS_ANIMATIONS",
- "at": "com\/android\/server\/wm\/RecentsAnimation.java"
- },
"495032901": {
"message": "Expected target stack=%s to restored behind stack=%s but it is behind stack=%s",
"level": "WARN",
@@ -2575,12 +2581,6 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
- "875196661": {
- "message": "Skipping stack: (mismatch activity\/stack) %s",
- "level": "DEBUG",
- "group": "WM_DEBUG_TASKS",
- "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
- },
"883475718": {
"message": "Report configuration: %s %s %s",
"level": "VERBOSE",
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index 6ac73b1..bd0e56a 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -445,3 +445,11 @@
led 0x08 MISC
led 0x09 MAIL
led 0x0a CHARGING
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/Vendor_054c_Product_05c4.idc b/data/keyboards/Vendor_054c_Product_05c4.idc
new file mode 100644
index 0000000..2cb3f7b
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_05c4.idc
@@ -0,0 +1,35 @@
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Sony DS4 motion sensor configuration file.
+#
+
+# reporting mode 0 - continuous
+sensor.accelerometer.reportingMode = 0
+# The delay between sensor events corresponding to the lowest frequency in microsecond
+sensor.accelerometer.maxDelay = 100000
+# The minimum delay allowed between two events in microsecond
+sensor.accelerometer.minDelay = 5000
+# The power in mA used by this sensor while in use
+sensor.accelerometer.power = 1.5
+
+# reporting mode 0 - continuous
+sensor.gyroscope.reportingMode = 0
+# The delay between sensor events corresponding to the lowest frequency in microsecond
+sensor.gyroscope.maxDelay = 100000
+# The minimum delay allowed between two events in microsecond
+sensor.gyroscope.minDelay = 5000
+# The power in mA used by this sensor while in use
+sensor.gyroscope.power = 0.8
diff --git a/data/keyboards/Vendor_054c_Product_05c4.kl b/data/keyboards/Vendor_054c_Product_05c4.kl
index cd7ab1f..c8b4fc3 100644
--- a/data/keyboards/Vendor_054c_Product_05c4.kl
+++ b/data/keyboards/Vendor_054c_Product_05c4.kl
@@ -68,3 +68,11 @@
# and this button will be equivalent to left mouse button
# Therefore, map it to KEYCODE_BUTTON_1 here to allow apps to still handle this on earlier versions
key 0x13d BUTTON_1
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/Vendor_054c_Product_05c4_Version_8000.kl b/data/keyboards/Vendor_054c_Product_05c4_Version_8000.kl
index 19fcb86..a877c4c 100644
--- a/data/keyboards/Vendor_054c_Product_05c4_Version_8000.kl
+++ b/data/keyboards/Vendor_054c_Product_05c4_Version_8000.kl
@@ -66,3 +66,11 @@
# In kernel versions >= 4.10, the touchpad is a separate input device,
# so the touchpad button click will not be covered by this layout.
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/Vendor_054c_Product_05c4_Version_8100.kl b/data/keyboards/Vendor_054c_Product_05c4_Version_8100.kl
index 19fcb86..a877c4c 100644
--- a/data/keyboards/Vendor_054c_Product_05c4_Version_8100.kl
+++ b/data/keyboards/Vendor_054c_Product_05c4_Version_8100.kl
@@ -66,3 +66,11 @@
# In kernel versions >= 4.10, the touchpad is a separate input device,
# so the touchpad button click will not be covered by this layout.
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/Vendor_054c_Product_05c4_Version_8111.kl b/data/keyboards/Vendor_054c_Product_05c4_Version_8111.kl
index d38bdec..1473c4e 100644
--- a/data/keyboards/Vendor_054c_Product_05c4_Version_8111.kl
+++ b/data/keyboards/Vendor_054c_Product_05c4_Version_8111.kl
@@ -66,3 +66,11 @@
# In kernel versions >= 4.10, the touchpad is a separate input device,
# so the touchpad button click will not be covered by this layout.
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/Vendor_054c_Product_09cc.idc b/data/keyboards/Vendor_054c_Product_09cc.idc
new file mode 100644
index 0000000..2cb3f7b
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_09cc.idc
@@ -0,0 +1,35 @@
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Sony DS4 motion sensor configuration file.
+#
+
+# reporting mode 0 - continuous
+sensor.accelerometer.reportingMode = 0
+# The delay between sensor events corresponding to the lowest frequency in microsecond
+sensor.accelerometer.maxDelay = 100000
+# The minimum delay allowed between two events in microsecond
+sensor.accelerometer.minDelay = 5000
+# The power in mA used by this sensor while in use
+sensor.accelerometer.power = 1.5
+
+# reporting mode 0 - continuous
+sensor.gyroscope.reportingMode = 0
+# The delay between sensor events corresponding to the lowest frequency in microsecond
+sensor.gyroscope.maxDelay = 100000
+# The minimum delay allowed between two events in microsecond
+sensor.gyroscope.minDelay = 5000
+# The power in mA used by this sensor while in use
+sensor.gyroscope.power = 0.8
diff --git a/data/keyboards/Vendor_054c_Product_09cc.kl b/data/keyboards/Vendor_054c_Product_09cc.kl
index cd7ab1f..c8b4fc3 100644
--- a/data/keyboards/Vendor_054c_Product_09cc.kl
+++ b/data/keyboards/Vendor_054c_Product_09cc.kl
@@ -68,3 +68,11 @@
# and this button will be equivalent to left mouse button
# Therefore, map it to KEYCODE_BUTTON_1 here to allow apps to still handle this on earlier versions
key 0x13d BUTTON_1
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/Vendor_054c_Product_09cc_Version_8000.kl b/data/keyboards/Vendor_054c_Product_09cc_Version_8000.kl
index 19fcb86..a877c4c 100644
--- a/data/keyboards/Vendor_054c_Product_09cc_Version_8000.kl
+++ b/data/keyboards/Vendor_054c_Product_09cc_Version_8000.kl
@@ -66,3 +66,11 @@
# In kernel versions >= 4.10, the touchpad is a separate input device,
# so the touchpad button click will not be covered by this layout.
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/Vendor_054c_Product_09cc_Version_8100.kl b/data/keyboards/Vendor_054c_Product_09cc_Version_8100.kl
index 19fcb86..a877c4c 100644
--- a/data/keyboards/Vendor_054c_Product_09cc_Version_8100.kl
+++ b/data/keyboards/Vendor_054c_Product_09cc_Version_8100.kl
@@ -66,3 +66,11 @@
# In kernel versions >= 4.10, the touchpad is a separate input device,
# so the touchpad button click will not be covered by this layout.
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/Vendor_054c_Product_09cc_Version_8111.kl b/data/keyboards/Vendor_054c_Product_09cc_Version_8111.kl
index d38bdec..1473c4e 100644
--- a/data/keyboards/Vendor_054c_Product_09cc_Version_8111.kl
+++ b/data/keyboards/Vendor_054c_Product_09cc_Version_8111.kl
@@ -66,3 +66,11 @@
# In kernel versions >= 4.10, the touchpad is a separate input device,
# so the touchpad button click will not be covered by this layout.
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/keyboards.mk b/data/keyboards/keyboards.mk
index 68cbd29..c7ce8cd 100644
--- a/data/keyboards/keyboards.mk
+++ b/data/keyboards/keyboards.mk
@@ -14,13 +14,9 @@
# Warning: this is actually a product definition, to be inherited from
-include $(LOCAL_PATH)/common.mk
+PRODUCT_COPY_FILES := \
+ $(call find-copy-subdir-files,*.kl,$(LOCAL_PATH),system/usr/keylayout) \
+ $(call find-copy-subdir-files,*.kcm,$(LOCAL_PATH),system/usr/keychars) \
+ $(call find-copy-subdir-files,*.idc,$(LOCAL_PATH),system/usr/idc)
-PRODUCT_COPY_FILES := $(foreach file,$(framework_keylayouts),\
- $(file):system/usr/keylayout/$(notdir $(file)))
-PRODUCT_COPY_FILES += $(foreach file,$(framework_keycharmaps),\
- $(file):system/usr/keychars/$(notdir $(file)))
-
-PRODUCT_COPY_FILES += $(foreach file,$(framework_keyconfigs),\
- $(file):system/usr/idc/$(notdir $(file)))
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStore3DESCipherSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStore3DESCipherSpi.java
index 0775a1a..56f7ea8 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStore3DESCipherSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStore3DESCipherSpi.java
@@ -41,7 +41,7 @@
*
* @hide
*/
-public class AndroidKeyStore3DESCipherSpi extends AndroidKeyStoreCipherSpiBase {
+public abstract class AndroidKeyStore3DESCipherSpi extends AndroidKeyStoreCipherSpiBase {
private static final int BLOCK_SIZE_BYTES = 8;
@@ -73,12 +73,22 @@
public NoPadding() {
super(KeymasterDefs.KM_PAD_NONE);
}
+
+ @Override
+ protected final String getTransform() {
+ return "DESede/ECB/NoPadding";
+ }
}
public static class PKCS7Padding extends ECB {
public PKCS7Padding() {
super(KeymasterDefs.KM_PAD_PKCS7);
}
+
+ @Override
+ protected final String getTransform() {
+ return "DESede/ECB/PKCS7Padding";
+ }
}
}
@@ -91,12 +101,23 @@
public NoPadding() {
super(KeymasterDefs.KM_PAD_NONE);
}
+
+ @Override
+ protected final String getTransform() {
+ return "DESede/CBC/NoPadding";
+ }
+
}
public static class PKCS7Padding extends CBC {
public PKCS7Padding() {
super(KeymasterDefs.KM_PAD_PKCS7);
}
+
+ @Override
+ protected final String getTransform() {
+ return "DESede/CBC/PKCS7Padding";
+ }
}
}
@@ -288,7 +309,7 @@
if (parameters != null) {
for (KeyParameter p : parameters) {
if (p.tag == KeymasterDefs.KM_TAG_NONCE) {
- returnedIv = p.blob;
+ returnedIv = p.value.getBlob();
break;
}
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreAuthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreAuthenticatedAESCipherSpi.java
index bc56f01..64da837 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreAuthenticatedAESCipherSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreAuthenticatedAESCipherSpi.java
@@ -64,6 +64,11 @@
}
@Override
+ protected final String getTransform() {
+ return "AES/GCM/NoPadding";
+ }
+
+ @Override
protected final void resetAll() {
mTagLengthBits = DEFAULT_TAG_LENGTH_BITS;
super.resetAll();
@@ -325,7 +330,7 @@
if (parameters != null) {
for (KeyParameter p : parameters) {
if (p.tag == KeymasterDefs.KM_TAG_NONCE) {
- returnedIv = p.blob;
+ returnedIv = p.value.getBlob();
break;
}
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java
index dd943d4..9ad6f3a 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java
@@ -254,13 +254,13 @@
private void putAsymmetricCipherImpl(String transformation, String implClass) {
put("Cipher." + transformation, implClass);
put("Cipher." + transformation + " SupportedKeyClasses",
- KEYSTORE_PRIVATE_KEY_CLASS_NAME + "|" + KEYSTORE_PUBLIC_KEY_CLASS_NAME);
+ KEYSTORE_PRIVATE_KEY_CLASS_NAME);
}
private void putSignatureImpl(String algorithm, String implClass) {
put("Signature." + algorithm, implClass);
put("Signature." + algorithm + " SupportedKeyClasses",
- KEYSTORE_PRIVATE_KEY_CLASS_NAME + "|" + KEYSTORE_PUBLIC_KEY_CLASS_NAME);
+ KEYSTORE_PRIVATE_KEY_CLASS_NAME);
}
public static String[] getSupportedEcdsaSignatureDigests() {
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
index a3b04ab..2ee952c 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
@@ -43,6 +43,7 @@
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidKeySpecException;
+import java.security.spec.MGF1ParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
@@ -57,6 +58,8 @@
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.ShortBufferException;
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
import javax.crypto.spec.SecretKeySpec;
/**
@@ -99,6 +102,8 @@
*/
private Exception mCachedException;
+ private Cipher mCipher;
+
AndroidKeyStoreCipherSpiBase() {
mOperation = null;
mEncrypting = false;
@@ -110,6 +115,7 @@
mAdditionalAuthenticationDataStreamer = null;
mAdditionalAuthenticationDataStreamerClosed = false;
mCachedException = null;
+ mCipher = null;
}
@Override
@@ -117,6 +123,45 @@
throws InvalidKeyException {
resetAll();
+ if (!(key instanceof AndroidKeyStorePrivateKey
+ || key instanceof AndroidKeyStoreSecretKey)) {
+ try {
+ mCipher = Cipher.getInstance(getTransform());
+ String transform = getTransform();
+
+ if ("RSA/ECB/OAEPWithSHA-224AndMGF1Padding".equals(transform)) {
+ OAEPParameterSpec spec =
+ new OAEPParameterSpec("SHA-224", "MGF1",
+ new MGF1ParameterSpec("SHA1"), PSource.PSpecified.DEFAULT);
+ mCipher.init(opmode, key, spec, random);
+ } else if ("RSA/ECB/OAEPWithSHA-256AndMGF1Padding".equals(transform)) {
+ OAEPParameterSpec spec =
+ new OAEPParameterSpec("SHA-256", "MGF1",
+ new MGF1ParameterSpec("SHA1"), PSource.PSpecified.DEFAULT);
+ mCipher.init(opmode, key, spec, random);
+
+ } else if ("RSA/ECB/OAEPWithSHA-384AndMGF1Padding".equals(transform)) {
+ OAEPParameterSpec spec =
+ new OAEPParameterSpec("SHA-384", "MGF1",
+ new MGF1ParameterSpec("SHA1"), PSource.PSpecified.DEFAULT);
+ mCipher.init(opmode, key, spec, random);
+
+ } else if ("RSA/ECB/OAEPWithSHA-512AndMGF1Padding".equals(transform)) {
+ OAEPParameterSpec spec =
+ new OAEPParameterSpec("SHA-512", "MGF1",
+ new MGF1ParameterSpec("SHA1"), PSource.PSpecified.DEFAULT);
+ mCipher.init(opmode, key, spec, random);
+ } else {
+ mCipher.init(opmode, key, random);
+ }
+ return;
+ } catch (NoSuchAlgorithmException
+ | NoSuchPaddingException
+ | InvalidAlgorithmParameterException e) {
+ throw new InvalidKeyException(e);
+ }
+ }
+
boolean success = false;
try {
init(opmode, key, random);
@@ -139,6 +184,17 @@
SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
resetAll();
+ if (!(key instanceof AndroidKeyStorePrivateKey
+ || key instanceof AndroidKeyStoreSecretKey)) {
+ try {
+ mCipher = Cipher.getInstance(getTransform());
+ mCipher.init(opmode, key, params, random);
+ return;
+ } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
+ throw new InvalidKeyException(e);
+ }
+ }
+
boolean success = false;
try {
init(opmode, key, random);
@@ -157,6 +213,17 @@
SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
resetAll();
+ if (!(key instanceof AndroidKeyStorePrivateKey
+ || key instanceof AndroidKeyStoreSecretKey)) {
+ try {
+ mCipher = Cipher.getInstance(getTransform());
+ mCipher.init(opmode, key, params, random);
+ return;
+ } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
+ throw new InvalidKeyException(e);
+ }
+ }
+
boolean success = false;
try {
init(opmode, key, random);
@@ -214,6 +281,7 @@
mAdditionalAuthenticationDataStreamer = null;
mAdditionalAuthenticationDataStreamerClosed = false;
mCachedException = null;
+ mCipher = null;
}
/**
@@ -320,6 +388,10 @@
@Override
protected final byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
+ if (mCipher != null) {
+ return mCipher.update(input, inputOffset, inputLen);
+ }
+
if (mCachedException != null) {
return null;
}
@@ -371,6 +443,9 @@
@Override
protected final int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output,
int outputOffset) throws ShortBufferException {
+ if (mCipher != null) {
+ return mCipher.update(input, inputOffset, inputLen, output);
+ }
byte[] outputCopy = engineUpdate(input, inputOffset, inputLen);
if (outputCopy == null) {
return 0;
@@ -387,6 +462,10 @@
@Override
protected final int engineUpdate(ByteBuffer input, ByteBuffer output)
throws ShortBufferException {
+ if (mCipher != null) {
+ return mCipher.update(input, output);
+ }
+
if (input == null) {
throw new NullPointerException("input == null");
}
@@ -423,6 +502,11 @@
@Override
protected final void engineUpdateAAD(byte[] input, int inputOffset, int inputLen) {
+ if (mCipher != null) {
+ mCipher.updateAAD(input, inputOffset, inputLen);
+ return;
+ }
+
if (mCachedException != null) {
return;
}
@@ -459,6 +543,11 @@
@Override
protected final void engineUpdateAAD(ByteBuffer src) {
+ if (mCipher != null) {
+ mCipher.updateAAD(src);
+ return;
+ }
+
if (src == null) {
throw new IllegalArgumentException("src == null");
}
@@ -486,6 +575,10 @@
@Override
protected final byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
throws IllegalBlockSizeException, BadPaddingException {
+ if (mCipher != null) {
+ return mCipher.doFinal(input, inputOffset, inputLen);
+ }
+
if (mCachedException != null) {
throw (IllegalBlockSizeException)
new IllegalBlockSizeException().initCause(mCachedException);
@@ -522,6 +615,10 @@
protected final int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output,
int outputOffset) throws ShortBufferException, IllegalBlockSizeException,
BadPaddingException {
+ if (mCipher != null) {
+ return mCipher.doFinal(input, inputOffset, inputLen, output);
+ }
+
byte[] outputCopy = engineDoFinal(input, inputOffset, inputLen);
if (outputCopy == null) {
return 0;
@@ -538,6 +635,10 @@
@Override
protected final int engineDoFinal(ByteBuffer input, ByteBuffer output)
throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
+ if (mCipher != null) {
+ return mCipher.doFinal(input, output);
+ }
+
if (input == null) {
throw new NullPointerException("input == null");
}
@@ -575,6 +676,10 @@
@Override
protected final byte[] engineWrap(Key key)
throws IllegalBlockSizeException, InvalidKeyException {
+ if (mCipher != null) {
+ return mCipher.wrap(key);
+ }
+
if (mKey == null) {
throw new IllegalStateException("Not initilized");
}
@@ -656,6 +761,10 @@
@Override
protected final Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
int wrappedKeyType) throws InvalidKeyException, NoSuchAlgorithmException {
+ if (mCipher != null) {
+ return mCipher.unwrap(wrappedKey, wrappedKeyAlgorithm, wrappedKeyType);
+ }
+
if (mKey == null) {
throw new IllegalStateException("Not initilized");
}
@@ -902,4 +1011,6 @@
*/
protected abstract void loadAlgorithmSpecificParametersFromBeginResult(
KeyParameter[] parameters);
+
+ protected abstract String getTransform();
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java
index d1ef1df..8289671 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java
@@ -44,6 +44,11 @@
}
@Override
+ protected String getAlgorithm() {
+ return "NONEwithECDSA";
+ }
+
+ @Override
protected KeyStoreCryptoOperationStreamer createMainDataStreamer(
KeyStoreOperation operation) {
return new TruncateToFieldSizeMessageStreamer(
@@ -113,30 +118,50 @@
public SHA1() {
super(KeymasterDefs.KM_DIGEST_SHA1);
}
+ @Override
+ protected String getAlgorithm() {
+ return "SHA1withECDSA";
+ }
}
public final static class SHA224 extends AndroidKeyStoreECDSASignatureSpi {
public SHA224() {
super(KeymasterDefs.KM_DIGEST_SHA_2_224);
}
+ @Override
+ protected String getAlgorithm() {
+ return "SHA224withECDSA";
+ }
}
public final static class SHA256 extends AndroidKeyStoreECDSASignatureSpi {
public SHA256() {
super(KeymasterDefs.KM_DIGEST_SHA_2_256);
}
+ @Override
+ protected String getAlgorithm() {
+ return "SHA256withECDSA";
+ }
}
public final static class SHA384 extends AndroidKeyStoreECDSASignatureSpi {
public SHA384() {
super(KeymasterDefs.KM_DIGEST_SHA_2_384);
}
+ @Override
+ protected String getAlgorithm() {
+ return "SHA384withECDSA";
+ }
}
public final static class SHA512 extends AndroidKeyStoreECDSASignatureSpi {
public SHA512() {
super(KeymasterDefs.KM_DIGEST_SHA_2_512);
}
+ @Override
+ protected String getAlgorithm() {
+ return "SHA512withECDSA";
+ }
}
private final int mKeymasterDigest;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index b2e32a3..403da18 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -31,9 +31,7 @@
import android.system.keystore2.KeyMetadata;
import android.system.keystore2.ResponseCode;
-import java.security.KeyFactory;
import java.security.KeyPair;
-import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.ProviderException;
import java.security.PublicKey;
@@ -42,8 +40,6 @@
import java.security.UnrecoverableKeyException;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPublicKey;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import javax.crypto.Mac;
@@ -237,28 +233,11 @@
throw new UnrecoverableKeyException("Failed to obtain X.509 form of public key."
+ " Keystore has no public certificate stored.");
}
- final byte[] x509EncodedPublicKey = metadata.certificate;
+ final byte[] x509PublicCert = metadata.certificate;
- String jcaKeyAlgorithm;
- try {
- jcaKeyAlgorithm = KeyProperties.KeyAlgorithm.fromKeymasterAsymmetricKeyAlgorithm(
- algorithm);
- } catch (IllegalArgumentException e) {
- throw (UnrecoverableKeyException)
- new UnrecoverableKeyException("Failed to load private key")
- .initCause(e);
- }
+ PublicKey publicKey = AndroidKeyStoreSpi.toCertificate(x509PublicCert).getPublicKey();
- PublicKey publicKey;
- try {
- KeyFactory keyFactory = KeyFactory.getInstance(jcaKeyAlgorithm);
- publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(x509EncodedPublicKey));
- } catch (NoSuchAlgorithmException e) {
- throw new ProviderException(
- "Failed to obtain " + jcaKeyAlgorithm + " KeyFactory", e);
- } catch (InvalidKeySpecException e) {
- throw new ProviderException("Invalid X.509 encoding of public key", e);
- }
+ String jcaKeyAlgorithm = publicKey.getAlgorithm();
KeyStoreSecurityLevel securityLevel = iSecurityLevel;
if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(jcaKeyAlgorithm)) {
@@ -358,7 +337,7 @@
KeyDescriptor descriptor = new KeyDescriptor();
if (namespace == KeyProperties.NAMESPACE_APPLICATION) {
- descriptor.nspace = 0; // ignored;
+ descriptor.nspace = KeyProperties.NAMESPACE_APPLICATION; // ignored;
descriptor.domain = Domain.APP;
} else {
descriptor.nspace = namespace;
@@ -387,10 +366,10 @@
for (Authorization a : response.metadata.authorizations) {
switch (a.keyParameter.tag) {
case KeymasterDefs.KM_TAG_ALGORITHM:
- keymasterAlgorithm = a.keyParameter.integer;
+ keymasterAlgorithm = a.keyParameter.value.getAlgorithm();
break;
case KeymasterDefs.KM_TAG_DIGEST:
- if (keymasterDigest == -1) keymasterDigest = a.keyParameter.integer;
+ if (keymasterDigest == -1) keymasterDigest = a.keyParameter.value.getDigest();
break;
}
}
@@ -407,7 +386,7 @@
keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_EC) {
return makeAndroidKeyStorePublicKeyFromKeyEntryResponse(descriptor, response.metadata,
new KeyStoreSecurityLevel(response.iSecurityLevel),
- keymasterAlgorithm);
+ keymasterAlgorithm).getPrivateKey();
} else {
throw new UnrecoverableKeyException("Key algorithm unknown");
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
index 951f918..6ff9432 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
@@ -158,7 +158,7 @@
}
/**
- * RSA cipher with OAEP encryption padding. Only SHA-1 based MGF1 is supported as MGF.
+ * RSA cipher with OAEP encryption padding.
*/
abstract static class OAEPWithMGF1Padding extends AndroidKeyStoreRSACipherSpi {
@@ -316,6 +316,25 @@
protected final int getAdditionalEntropyAmountForFinish() {
return (isEncrypting()) ? mDigestOutputSizeBytes : 0;
}
+
+ @Override
+ protected final String getTransform() {
+ switch (mKeymasterDigest) {
+ case KeymasterDefs.KM_DIGEST_SHA1:
+ return "RSA/ECB/OAEPWithSHA-1AndMGF1Padding";
+ case KeymasterDefs.KM_DIGEST_SHA_2_224:
+ return "RSA/ECB/OAEPWithSHA-224AndMGF1Padding";
+ case KeymasterDefs.KM_DIGEST_SHA_2_256:
+ return "RSA/ECB/OAEPWithSHA-256AndMGF1Padding";
+ case KeymasterDefs.KM_DIGEST_SHA_2_384:
+ return "RSA/ECB/OAEPWithSHA-384AndMGF1Padding";
+ case KeymasterDefs.KM_DIGEST_SHA_2_512:
+ return "RSA/ECB/OAEPWithSHA-512AndMGF1Padding";
+ default:
+ return "RSA/ECB/OAEPPadding";
+ }
+ }
+
}
public static class OAEPWithSHA1AndMGF1Padding extends OAEPWithMGF1Padding {
@@ -358,6 +377,11 @@
}
@Override
+ protected String getTransform() {
+ return "RSA/ECB/" + KeyProperties.EncryptionPadding.fromKeymaster(mKeymasterPadding);
+ }
+
+ @Override
protected final void initKey(int opmode, Key key) throws InvalidKeyException {
if (key == null) {
throw new InvalidKeyException("Unsupported key: null");
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreRSASignatureSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreRSASignatureSpi.java
index ab75591..931c2f8 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreRSASignatureSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreRSASignatureSpi.java
@@ -48,42 +48,70 @@
public NONEWithPKCS1Padding() {
super(KeymasterDefs.KM_DIGEST_NONE);
}
+ @Override
+ protected String getAlgorithm() {
+ return "NONEwithRSA";
+ }
}
public static final class MD5WithPKCS1Padding extends PKCS1Padding {
public MD5WithPKCS1Padding() {
super(KeymasterDefs.KM_DIGEST_MD5);
}
+ @Override
+ protected String getAlgorithm() {
+ return "MD5withRSA";
+ }
}
public static final class SHA1WithPKCS1Padding extends PKCS1Padding {
public SHA1WithPKCS1Padding() {
super(KeymasterDefs.KM_DIGEST_SHA1);
}
+ @Override
+ protected String getAlgorithm() {
+ return "SHA1withRSA";
+ }
}
public static final class SHA224WithPKCS1Padding extends PKCS1Padding {
public SHA224WithPKCS1Padding() {
super(KeymasterDefs.KM_DIGEST_SHA_2_224);
}
+ @Override
+ protected String getAlgorithm() {
+ return "SHA224withRSA";
+ }
}
public static final class SHA256WithPKCS1Padding extends PKCS1Padding {
public SHA256WithPKCS1Padding() {
super(KeymasterDefs.KM_DIGEST_SHA_2_256);
}
+ @Override
+ protected String getAlgorithm() {
+ return "SHA256withRSA";
+ }
}
public static final class SHA384WithPKCS1Padding extends PKCS1Padding {
public SHA384WithPKCS1Padding() {
super(KeymasterDefs.KM_DIGEST_SHA_2_384);
}
+ @Override
+ protected String getAlgorithm() {
+ return "SHA384withRSA";
+ }
}
public static final class SHA512WithPKCS1Padding extends PKCS1Padding {
public SHA512WithPKCS1Padding() {
super(KeymasterDefs.KM_DIGEST_SHA_2_512);
}
+ @Override
+ protected String getAlgorithm() {
+ return "SHA512withRSA";
+ }
}
abstract static class PSSPadding extends AndroidKeyStoreRSASignatureSpi {
@@ -103,30 +131,50 @@
public SHA1WithPSSPadding() {
super(KeymasterDefs.KM_DIGEST_SHA1);
}
+ @Override
+ protected String getAlgorithm() {
+ return "SHA1withRSA/PSS";
+ }
}
public static final class SHA224WithPSSPadding extends PSSPadding {
public SHA224WithPSSPadding() {
super(KeymasterDefs.KM_DIGEST_SHA_2_224);
}
+ @Override
+ protected String getAlgorithm() {
+ return "SHA224withRSA/PSS";
+ }
}
public static final class SHA256WithPSSPadding extends PSSPadding {
public SHA256WithPSSPadding() {
super(KeymasterDefs.KM_DIGEST_SHA_2_256);
}
+ @Override
+ protected String getAlgorithm() {
+ return "SHA256withRSA/PSS";
+ }
}
public static final class SHA384WithPSSPadding extends PSSPadding {
public SHA384WithPSSPadding() {
super(KeymasterDefs.KM_DIGEST_SHA_2_384);
}
+ @Override
+ protected String getAlgorithm() {
+ return "SHA384withRSA/PSS";
+ }
}
public static final class SHA512WithPSSPadding extends PSSPadding {
public SHA512WithPSSPadding() {
super(KeymasterDefs.KM_DIGEST_SHA_2_512);
}
+ @Override
+ protected String getAlgorithm() {
+ return "SHA512withRSA/PSS";
+ }
}
private final int mKeymasterDigest;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java
index 9d3b970..74503e1 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -102,7 +102,8 @@
insideSecureHardware =
KeyStore2ParameterUtils.isSecureHardware(a.securityLevel);
securityLevel = a.securityLevel;
- origin = KeyProperties.Origin.fromKeymaster(a.keyParameter.integer);
+ origin = KeyProperties.Origin.fromKeymaster(
+ a.keyParameter.value.getOrigin());
break;
case KeymasterDefs.KM_TAG_KEY_SIZE:
long keySizeUnsigned = KeyStore2ParameterUtils.getUnsignedInt(a);
@@ -113,45 +114,51 @@
keySize = (int) keySizeUnsigned;
break;
case KeymasterDefs.KM_TAG_PURPOSE:
- purposes |= KeyProperties.Purpose.fromKeymaster(a.keyParameter.integer);
+ purposes |= KeyProperties.Purpose.fromKeymaster(
+ a.keyParameter.value.getKeyPurpose());
break;
case KeymasterDefs.KM_TAG_PADDING:
+ int paddingMode = a.keyParameter.value.getPaddingMode();
try {
- if (a.keyParameter.integer == KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN
- || a.keyParameter.integer == KeymasterDefs.KM_PAD_RSA_PSS) {
+ if (paddingMode == KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN
+ || paddingMode == KeymasterDefs.KM_PAD_RSA_PSS) {
@KeyProperties.SignaturePaddingEnum String padding =
KeyProperties.SignaturePadding.fromKeymaster(
- a.keyParameter.integer);
+ paddingMode);
signaturePaddingsList.add(padding);
} else {
@KeyProperties.EncryptionPaddingEnum String jcaPadding =
KeyProperties.EncryptionPadding.fromKeymaster(
- a.keyParameter.integer);
+ paddingMode);
encryptionPaddingsList.add(jcaPadding);
}
} catch (IllegalArgumentException e) {
throw new ProviderException("Unsupported padding: "
- + a.keyParameter.integer);
+ + paddingMode);
}
break;
case KeymasterDefs.KM_TAG_DIGEST:
- digestsList.add(KeyProperties.Digest.fromKeymaster(a.keyParameter.integer));
+ digestsList.add(KeyProperties.Digest.fromKeymaster(
+ a.keyParameter.value.getDigest()));
break;
case KeymasterDefs.KM_TAG_BLOCK_MODE:
blockModesList.add(
- KeyProperties.BlockMode.fromKeymaster(a.keyParameter.integer)
+ KeyProperties.BlockMode.fromKeymaster(
+ a.keyParameter.value.getBlockMode())
);
break;
case KeymasterDefs.KM_TAG_USER_AUTH_TYPE:
+ int authenticatorType = a.keyParameter.value.getHardwareAuthenticatorType();
if (KeyStore2ParameterUtils.isSecureHardware(a.securityLevel)) {
- keymasterHwEnforcedUserAuthenticators = a.keyParameter.integer;
+ keymasterHwEnforcedUserAuthenticators = authenticatorType;
} else {
- keymasterSwEnforcedUserAuthenticators = a.keyParameter.integer;
+ keymasterSwEnforcedUserAuthenticators = authenticatorType;
}
break;
case KeymasterDefs.KM_TAG_USER_SECURE_ID:
keymasterSecureUserIds.add(
- KeymasterArguments.toUint64(a.keyParameter.longInteger));
+ KeymasterArguments.toUint64(
+ a.keyParameter.value.getLongInteger()));
break;
case KeymasterDefs.KM_TAG_ACTIVE_DATETIME:
keyValidityStart = KeyStore2ParameterUtils.getDate(a);
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSignatureSpiBase.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSignatureSpiBase.java
index 9b4f01e..96da1e0 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSignatureSpiBase.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSignatureSpiBase.java
@@ -30,10 +30,12 @@
import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
import java.security.InvalidParameterException;
+import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.ProviderException;
import java.security.PublicKey;
import java.security.SecureRandom;
+import java.security.Signature;
import java.security.SignatureException;
import java.security.SignatureSpi;
import java.util.ArrayList;
@@ -76,6 +78,13 @@
*/
private Exception mCachedException;
+ /**
+ * This signature object is used for public key operations, i.e, signatrue verification.
+ * The Android Keystore backend does not perform public key operations and defers to the
+ * Highest priority provider.
+ */
+ private Signature mSignature;
+
AndroidKeyStoreSignatureSpiBase() {
mOperation = null;
mOperationChallenge = 0;
@@ -84,6 +93,7 @@
appRandom = null;
mMessageStreamer = null;
mCachedException = null;
+ mSignature = null;
}
@Override
@@ -123,27 +133,13 @@
protected final void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
resetAll();
- boolean success = false;
try {
- if (publicKey == null) {
- throw new InvalidKeyException("Unsupported key: null");
- }
- AndroidKeyStoreKey keystoreKey;
- if (publicKey instanceof AndroidKeyStorePublicKey) {
- keystoreKey = (AndroidKeyStorePublicKey) publicKey;
- } else {
- throw new InvalidKeyException("Unsupported public key type: " + publicKey);
- }
- mSigning = false;
- initKey(keystoreKey);
- appRandom = null;
- ensureKeystoreOperationInitialized();
- success = true;
- } finally {
- if (!success) {
- resetAll();
- }
+ mSignature = Signature.getInstance(getAlgorithm());
+ } catch (NoSuchAlgorithmException e) {
+ throw new InvalidKeyException(e);
}
+
+ mSignature.initVerify(publicKey);
}
/**
@@ -251,6 +247,11 @@
@Override
protected final void engineUpdate(byte[] b, int off, int len) throws SignatureException {
+ if (mSignature != null) {
+ mSignature.update(b, off, len);
+ return;
+ }
+
if (mCachedException != null) {
throw new SignatureException(mCachedException);
}
@@ -337,39 +338,10 @@
@Override
protected final boolean engineVerify(byte[] signature) throws SignatureException {
- if (mCachedException != null) {
- throw new SignatureException(mCachedException);
+ if (mSignature != null) {
+ return mSignature.verify(signature);
}
-
- try {
- ensureKeystoreOperationInitialized();
- } catch (InvalidKeyException e) {
- throw new SignatureException(e);
- }
-
- boolean verified;
- try {
- byte[] output = mMessageStreamer.doFinal(
- EmptyArray.BYTE, 0, 0,
- signature);
- if (output.length != 0) {
- throw new ProviderException(
- "Signature verification unexpected produced output: " + output.length
- + " bytes");
- }
- verified = true;
- } catch (KeyStoreException e) {
- switch (e.getErrorCode()) {
- case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED:
- verified = false;
- break;
- default:
- throw new SignatureException(e);
- }
- }
-
- resetWhilePreservingInitState();
- return verified;
+ throw new IllegalStateException("Not initialised.");
}
@Override
@@ -392,6 +364,13 @@
}
/**
+ * Implementations need to report the algorithm they implement so that we can delegate to the
+ * highest priority provider.
+ * @return Algorithm string.
+ */
+ protected abstract String getAlgorithm();
+
+ /**
* Returns {@code true} if this signature is initialized for signing, {@code false} if this
* signature is initialized for verification.
*/
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index c42c7b2..5e7f648 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -219,7 +219,7 @@
return null;
}
- private static X509Certificate toCertificate(byte[] bytes) {
+ static X509Certificate toCertificate(byte[] bytes) {
try {
final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
return (X509Certificate) certFactory.generateCertificate(
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreUnauthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreUnauthenticatedAESCipherSpi.java
index 4d4b0d8..5c048a1 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreUnauthenticatedAESCipherSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreUnauthenticatedAESCipherSpi.java
@@ -42,7 +42,7 @@
*
* @hide
*/
-class AndroidKeyStoreUnauthenticatedAESCipherSpi extends AndroidKeyStoreCipherSpiBase {
+abstract class AndroidKeyStoreUnauthenticatedAESCipherSpi extends AndroidKeyStoreCipherSpiBase {
abstract static class ECB extends AndroidKeyStoreUnauthenticatedAESCipherSpi {
protected ECB(int keymasterPadding) {
@@ -53,12 +53,22 @@
public NoPadding() {
super(KeymasterDefs.KM_PAD_NONE);
}
+
+ @Override
+ protected final String getTransform() {
+ return "AES/ECB/NoPadding";
+ }
}
public static class PKCS7Padding extends ECB {
public PKCS7Padding() {
super(KeymasterDefs.KM_PAD_PKCS7);
}
+
+ @Override
+ protected final String getTransform() {
+ return "AES/ECB/PKCS7Padding";
+ }
}
}
@@ -71,12 +81,22 @@
public NoPadding() {
super(KeymasterDefs.KM_PAD_NONE);
}
+
+ @Override
+ protected final String getTransform() {
+ return "AES/CBC/NoPadding";
+ }
}
public static class PKCS7Padding extends CBC {
public PKCS7Padding() {
super(KeymasterDefs.KM_PAD_PKCS7);
}
+
+ @Override
+ protected final String getTransform() {
+ return "AES/CBC/PKCS7Padding";
+ }
}
}
@@ -89,6 +109,11 @@
public NoPadding() {
super(KeymasterDefs.KM_PAD_NONE);
}
+
+ @Override
+ protected final String getTransform() {
+ return "AES/CTR/NoPadding";
+ }
}
}
@@ -275,7 +300,7 @@
if (parameters != null) {
for (KeyParameter p : parameters) {
if (p.tag == KeymasterDefs.KM_TAG_NONCE) {
- returnedIv = p.blob;
+ returnedIv = p.value.getBlob();
break;
}
}
diff --git a/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java b/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java
index 18c786a..4c8ab8d 100644
--- a/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java
+++ b/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java
@@ -19,7 +19,9 @@
import android.annotation.NonNull;
import android.hardware.biometrics.BiometricManager;
import android.hardware.security.keymint.KeyParameter;
+import android.hardware.security.keymint.KeyParameterValue;
import android.hardware.security.keymint.SecurityLevel;
+import android.hardware.security.keymint.Tag;
import android.security.GateKeeper;
import android.security.keymaster.KeymasterDefs;
import android.security.keystore.KeyProperties;
@@ -50,7 +52,7 @@
}
KeyParameter p = new KeyParameter();
p.tag = tag;
- p.boolValue = true;
+ p.value = KeyParameterValue.boolValue(true);
return p;
}
@@ -62,14 +64,40 @@
* @hide
*/
static @NonNull KeyParameter makeEnum(int tag, int v) {
- int type = KeymasterDefs.getTagType(tag);
- if (type != KeymasterDefs.KM_ENUM && type != KeymasterDefs.KM_ENUM_REP) {
- throw new IllegalArgumentException("Not an enum or repeatable enum tag: " + tag);
+ KeyParameter kp = new KeyParameter();
+ kp.tag = tag;
+ switch (tag) {
+ case Tag.PURPOSE:
+ kp.value = KeyParameterValue.keyPurpose(v);
+ break;
+ case Tag.ALGORITHM:
+ kp.value = KeyParameterValue.algorithm(v);
+ break;
+ case Tag.BLOCK_MODE:
+ kp.value = KeyParameterValue.blockMode(v);
+ break;
+ case Tag.DIGEST:
+ kp.value = KeyParameterValue.digest(v);
+ break;
+ case Tag.EC_CURVE:
+ kp.value = KeyParameterValue.ecCurve(v);
+ break;
+ case Tag.ORIGIN:
+ kp.value = KeyParameterValue.origin(v);
+ break;
+ case Tag.PADDING:
+ kp.value = KeyParameterValue.paddingMode(v);
+ break;
+ case Tag.USER_AUTH_TYPE:
+ kp.value = KeyParameterValue.hardwareAuthenticatorType(v);
+ break;
+ case Tag.HARDWARE_TYPE:
+ kp.value = KeyParameterValue.securityLevel(v);
+ break;
+ default:
+ throw new IllegalArgumentException("Not an enum or repeatable enum tag: " + tag);
}
- KeyParameter p = new KeyParameter();
- p.tag = tag;
- p.integer = v;
- return p;
+ return kp;
}
/**
@@ -86,7 +114,7 @@
}
KeyParameter p = new KeyParameter();
p.tag = tag;
- p.integer = v;
+ p.value = KeyParameterValue.integer(v);
return p;
}
@@ -104,7 +132,7 @@
}
KeyParameter p = new KeyParameter();
p.tag = tag;
- p.longInteger = v;
+ p.value = KeyParameterValue.longInteger(v);
return p;
}
@@ -121,7 +149,7 @@
}
KeyParameter p = new KeyParameter();
p.tag = tag;
- p.blob = b;
+ p.value = KeyParameterValue.blob(b);
return p;
}
@@ -138,9 +166,10 @@
}
KeyParameter p = new KeyParameter();
p.tag = tag;
- p.longInteger = date.getTime();
- if (p.longInteger < 0) {
- throw new IllegalArgumentException("Date tag value out of range: " + p.longInteger);
+ p.value = KeyParameterValue.dateTime(date.getTime());
+ if (p.value.getDateTime() < 0) {
+ throw new IllegalArgumentException("Date tag value out of range: "
+ + p.value.getDateTime());
}
return p;
}
@@ -160,24 +189,24 @@
throw new IllegalArgumentException("Not an int tag: " + param.keyParameter.tag);
}
// KM_UINT is 32 bits wide so we must suppress sign extension.
- return ((long) param.keyParameter.integer) & 0xffffffffL;
+ return ((long) param.keyParameter.value.getInteger()) & 0xffffffffL;
}
static @NonNull Date getDate(@NonNull Authorization param) {
if (KeymasterDefs.getTagType(param.keyParameter.tag) != KeymasterDefs.KM_DATE) {
throw new IllegalArgumentException("Not a date tag: " + param.keyParameter.tag);
}
- if (param.keyParameter.longInteger < 0) {
+ if (param.keyParameter.value.getDateTime() < 0) {
throw new IllegalArgumentException("Date Value too large: "
- + param.keyParameter.longInteger);
+ + param.keyParameter.value.getDateTime());
}
- return new Date(param.keyParameter.longInteger);
+ return new Date(param.keyParameter.value.getDateTime());
}
static void forEachSetFlag(int flags, Consumer<Integer> consumer) {
int offset = 0;
while (flags != 0) {
- if ((flags & 1) == 0) {
+ if ((flags & 1) == 1) {
consumer.accept(1 << offset);
}
offset += 1;
diff --git a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
index 3b11854..f87a3d2 100644
--- a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
+++ b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
@@ -57,7 +57,7 @@
for (Authorization p : key.getAuthorizations()) {
switch(p.keyParameter.tag) {
case KeymasterDefs.KM_TAG_USER_SECURE_ID:
- keySids.add(p.keyParameter.longInteger);
+ keySids.add(p.keyParameter.value.getLongInteger());
break;
default:
break;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 8d15080..faa4a0e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -34,6 +34,7 @@
import android.util.SparseArray;
import android.view.SurfaceControl;
import android.window.ITaskOrganizerController;
+import android.window.StartingWindowInfo;
import android.window.TaskAppearedInfo;
import android.window.TaskOrganizer;
@@ -112,7 +113,7 @@
// TODO(b/131727939) temporarily live here, the starting surface drawer should be controlled
// by a controller, that class should be create while porting
// ActivityRecord#addStartingWindow to WMShell.
- mStartingSurfaceDrawer = new StartingSurfaceDrawer(context);
+ mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, mainExecutor);
}
@Override
@@ -229,13 +230,13 @@
}
@Override
- public void addStartingWindow(RunningTaskInfo taskInfo, IBinder appToken) {
- mStartingSurfaceDrawer.addStartingWindow(taskInfo, appToken);
+ public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
+ mStartingSurfaceDrawer.addStartingWindow(info, appToken);
}
@Override
- public void removeStartingWindow(RunningTaskInfo taskInfo) {
- mStartingSurfaceDrawer.removeStartingWindow(taskInfo);
+ public void removeStartingWindow(int taskId) {
+ mStartingSurfaceDrawer.removeStartingWindow(taskId);
}
@Override
@@ -261,6 +262,12 @@
synchronized (mLock) {
ProtoLog.v(WM_SHELL_TASK_ORG, "Task info changed taskId=%d", taskInfo.taskId);
final TaskAppearedInfo data = mTasks.get(taskInfo.taskId);
+ if (data == null) {
+ // TODO(b/171749427): It means onTaskInfoChanged send before onTaskAppeared or
+ // after onTaskVanished, it should be fixed in controller side.
+ return;
+ }
+
final TaskListener oldListener = getTaskListener(data.getTaskInfo());
final TaskListener newListener = getTaskListener(taskInfo);
mTasks.put(taskInfo.taskId, new TaskAppearedInfo(taskInfo, data.getLeash()));
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index 4c06a2c..616f24a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -339,9 +339,6 @@
public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {}
@Override
- public void dispatchPointerCaptureChanged(boolean hasCapture) {}
-
- @Override
public void requestScrollCapture(IScrollCaptureCallbacks callbacks) {
try {
callbacks.onUnavailable();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index d5db0cc..69d8db2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -32,6 +32,7 @@
import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Slog;
+import android.view.accessibility.AccessibilityManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -75,6 +76,7 @@
private final Handler mMainHandler = new Handler(Looper.getMainLooper());
private OneHandedDisplayAreaOrganizer mDisplayAreaOrganizer;
+ private final AccessibilityManager mAccessibilityManager;
/**
* Handle rotation based on OnDisplayChangingListener callback
@@ -164,6 +166,26 @@
}
};
+ private AccessibilityManager.AccessibilityStateChangeListener
+ mAccessibilityStateChangeListener =
+ new AccessibilityManager.AccessibilityStateChangeListener() {
+ @Override
+ public void onAccessibilityStateChanged(boolean enabled) {
+ if (enabled) {
+ final int mOneHandedTimeout = OneHandedSettingsUtil
+ .getSettingsOneHandedModeTimeout(mContext.getContentResolver());
+ final int timeout = mAccessibilityManager
+ .getRecommendedTimeoutMillis(mOneHandedTimeout * 1000
+ /* align with A11y timeout millis */,
+ AccessibilityManager.FLAG_CONTENT_CONTROLS);
+ mTimeoutHandler.setTimeout(timeout / 1000);
+ } else {
+ mTimeoutHandler.setTimeout(OneHandedSettingsUtil
+ .getSettingsOneHandedModeTimeout(mContext.getContentResolver()));
+ }
+ }
+ };
+
/**
* Creates {@link OneHandedController}, returns {@code null} if the feature is not supported.
*/
@@ -239,6 +261,11 @@
stopOneHanded(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT);
}
});
+
+ mAccessibilityManager = (AccessibilityManager)
+ context.getSystemService(Context.ACCESSIBILITY_SERVICE);
+ mAccessibilityManager.addAccessibilityStateChangeListener(
+ mAccessibilityStateChangeListener);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
index 4d66f29..f8217c6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
@@ -126,7 +126,7 @@
*/
public static boolean getSettingsSwipeToNotificationEnabled(ContentResolver resolver) {
return Settings.Secure.getInt(resolver,
- Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 0) == 1;
+ Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 1) == 1;
}
protected static void dump(PrintWriter pw, String prefix, ContentResolver resolver) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index fe01811..3362d2a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -22,6 +22,7 @@
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.graphics.Rect;
+import android.view.Choreographer;
import android.view.SurfaceControl;
import com.android.internal.annotations.VisibleForTesting;
@@ -327,8 +328,14 @@
mEndValue = endValue;
}
- SurfaceControl.Transaction newSurfaceControlTransaction() {
- return mSurfaceControlTransactionFactory.getTransaction();
+ /**
+ * @return {@link SurfaceControl.Transaction} instance with vsync-id.
+ */
+ protected SurfaceControl.Transaction newSurfaceControlTransaction() {
+ final SurfaceControl.Transaction tx =
+ mSurfaceControlTransactionFactory.getTransaction();
+ tx.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId());
+ return tx;
}
@VisibleForTesting
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
index 484592e..f839727 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
@@ -129,10 +129,9 @@
: getDefaultBounds();
final boolean useCurrentSize = reentryState != null && reentryState.getSize() != null;
- final Rect r = transformBoundsToAspectRatioIfValid(destinationBounds,
+ return transformBoundsToAspectRatioIfValid(destinationBounds,
mPipBoundsState.getAspectRatio(), false /* useCurrentMinEdgeSize */,
useCurrentSize);
- return r;
}
/** Returns the current bounds adjusted to the new aspect ratio, if valid. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
index 4493d38..d0d9b26 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
@@ -26,6 +26,7 @@
import android.view.DisplayInfo;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.function.TriConsumer;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
@@ -33,7 +34,6 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
-import java.util.function.BiConsumer;
/**
* Singleton source of truth for the current state of PIP bounds.
@@ -80,7 +80,7 @@
private boolean mHasUserResizedPip;
private @Nullable Runnable mOnMinimalSizeChangeCallback;
- private @Nullable BiConsumer<Boolean, Integer> mOnShelfVisibilityChangeCallback;
+ private @Nullable TriConsumer<Boolean, Integer, Boolean> mOnShelfVisibilityChangeCallback;
public PipBoundsState(@NonNull Context context) {
mContext = context;
@@ -310,6 +310,11 @@
/** Set whether the shelf is showing and its height. */
public void setShelfVisibility(boolean showing, int height) {
+ setShelfVisibility(showing, height, true);
+ }
+
+ /** Set whether the shelf is showing and its height. */
+ public void setShelfVisibility(boolean showing, int height, boolean updateMovementBounds) {
final boolean shelfShowing = showing && height > 0;
if (shelfShowing == mIsShelfShowing && height == mShelfHeight) {
return;
@@ -318,7 +323,8 @@
mIsShelfShowing = showing;
mShelfHeight = height;
if (mOnShelfVisibilityChangeCallback != null) {
- mOnShelfVisibilityChangeCallback.accept(mIsShelfShowing, mShelfHeight);
+ mOnShelfVisibilityChangeCallback.accept(mIsShelfShowing, mShelfHeight,
+ updateMovementBounds);
}
}
@@ -351,7 +357,7 @@
/** Set a callback to be notified when the shelf visibility changes. */
public void setOnShelfVisibilityChangeCallback(
- @Nullable BiConsumer<Boolean, Integer> onShelfVisibilityChangeCallback) {
+ @Nullable TriConsumer<Boolean, Integer, Boolean> onShelfVisibilityChangeCallback) {
mOnShelfVisibilityChangeCallback = onShelfVisibilityChangeCallback;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
index f8b4dd9..de3bb29 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
@@ -41,12 +41,12 @@
}
public void setTaskInfo(TaskInfo taskInfo) {
- if (taskInfo != null && taskInfo.topActivity != null) {
- mPackageName = taskInfo.topActivity.getPackageName();
- mPackageUid = getUid(mPackageName, taskInfo.userId);
- } else {
+ if (taskInfo == null) {
mPackageName = null;
mPackageUid = INVALID_PACKAGE_UID;
+ } else {
+ mPackageName = taskInfo.topActivity.getPackageName();
+ mPackageUid = getUid(mPackageName, taskInfo.userId);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 4d27602..fa88084 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -114,14 +114,14 @@
// the bounds for the next orientation using the destination bounds of the animation
// TODO: Technically this should account for movement animation bounds as well
Rect currentBounds = mPipTaskOrganizer.getCurrentOrAnimatingBounds();
- final boolean changed = onDisplayRotationChanged(mContext,
- mPipBoundsState.getNormalBounds(), currentBounds, mTmpInsetBounds, displayId,
- fromRotation, toRotation, t);
+ final Rect outBounds = new Rect();
+ final boolean changed = onDisplayRotationChanged(mContext, outBounds, currentBounds,
+ mTmpInsetBounds, displayId, fromRotation, toRotation, t);
if (changed) {
// If the pip was in the offset zone earlier, adjust the new bounds to the bottom of the
// movement bounds
- mTouchHandler.adjustBoundsForRotation(mPipBoundsState.getNormalBounds(),
- mPipBoundsState.getBounds(), mTmpInsetBounds);
+ mTouchHandler.adjustBoundsForRotation(outBounds, mPipBoundsState.getBounds(),
+ mTmpInsetBounds);
// The bounds are being applied to a specific snap fraction, so reset any known offsets
// for the previous orientation before updating the movement bounds.
@@ -129,14 +129,18 @@
// not during the fixed rotation. In fixed rotation case, app is about to enter PiP
// and we need the offsets preserved to calculate the destination bounds.
if (!mIsInFixedRotation) {
- mPipBoundsState.setShelfVisibility(false /* showing */, 0 /* height */);
+ // Update the shelf visibility without updating the movement bounds. We're already
+ // updating them below with the |fromRotation| flag set, which is more accurate
+ // than using the |fromShelfAdjustment|.
+ mPipBoundsState.setShelfVisibility(false /* showing */, 0 /* height */,
+ false /* updateMovementBounds */);
mPipBoundsState.setImeVisibility(false /* showing */, 0 /* height */);
mTouchHandler.onShelfVisibilityChanged(false, 0);
mTouchHandler.onImeVisibilityChanged(false, 0);
}
- updateMovementBounds(mPipBoundsState.getNormalBounds(), true /* fromRotation */,
- false /* fromImeAdjustment */, false /* fromShelfAdjustment */, t);
+ updateMovementBounds(outBounds, true /* fromRotation */, false /* fromImeAdjustment */,
+ false /* fromShelfAdjustment */, t);
}
};
@@ -248,12 +252,16 @@
false /* fromImeAdjustment */, false /* fromShelfAdjustment */,
null /* wct */);
});
- mPipBoundsState.setOnShelfVisibilityChangeCallback((isShowing, height) -> {
- mTouchHandler.onShelfVisibilityChanged(isShowing, height);
- updateMovementBounds(mPipBoundsState.getBounds(),
- false /* fromRotation */, false /* fromImeAdjustment */,
- true /* fromShelfAdjustment */, null /* windowContainerTransaction */);
- });
+ mPipBoundsState.setOnShelfVisibilityChangeCallback(
+ (isShowing, height, updateMovementBounds) -> {
+ mTouchHandler.onShelfVisibilityChanged(isShowing, height);
+ if (updateMovementBounds) {
+ updateMovementBounds(mPipBoundsState.getBounds(),
+ false /* fromRotation */, false /* fromImeAdjustment */,
+ true /* fromShelfAdjustment */,
+ null /* windowContainerTransaction */);
+ }
+ });
if (mTouchHandler != null) {
// Register the listener for input consumer touch events. Only for Phone
mPipInputConsumer.setInputListener(mTouchHandler::handleTouchEvent);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index ee79824..e144ca3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -16,11 +16,18 @@
package com.android.wm.shell.startingsurface;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.content.Context.CONTEXT_RESTRICTED;
import static android.content.res.Configuration.EMPTY;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
-import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityTaskManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
@@ -30,18 +37,20 @@
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManager;
-import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
+import android.os.RemoteException;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
+import android.window.StartingWindowInfo;
import android.window.TaskOrganizer;
+import android.window.TaskSnapshot;
import com.android.internal.R;
import com.android.internal.policy.PhoneWindow;
+import com.android.wm.shell.common.ShellExecutor;
import java.util.function.Consumer;
@@ -56,22 +65,24 @@
* @hide
*/
public class StartingSurfaceDrawer {
- private static final String TAG = StartingSurfaceDrawer.class.getSimpleName();
- private static final boolean DEBUG_SPLASH_SCREEN = false;
+ static final String TAG = StartingSurfaceDrawer.class.getSimpleName();
+ static final boolean DEBUG_SPLASH_SCREEN = false;
+ static final boolean DEBUG_TASK_SNAPSHOT = false;
private final Context mContext;
private final DisplayManager mDisplayManager;
+ final ShellExecutor mMainExecutor;
// TODO(b/131727939) remove this when clearing ActivityRecord
private static final int REMOVE_WHEN_TIMEOUT = 2000;
- public StartingSurfaceDrawer(Context context) {
+ public StartingSurfaceDrawer(Context context, ShellExecutor mainExecutor) {
mContext = context;
mDisplayManager = mContext.getSystemService(DisplayManager.class);
+ mMainExecutor = mainExecutor;
}
- private final Handler mHandler = new Handler(Looper.getMainLooper());
- private final SparseArray<TaskScreenView> mTaskScreenViews = new SparseArray<>();
+ private final SparseArray<StartingWindowRecord> mStartingWindowRecords = new SparseArray<>();
/** Obtain proper context for showing splash screen on the provided display. */
private Context getDisplayContext(Context context, int displayId) {
@@ -90,12 +101,111 @@
return context.createDisplayContext(targetDisplay);
}
+ private static class PreferredStartingTypeHelper {
+ private static final int STARTING_TYPE_NO = 0;
+ private static final int STARTING_TYPE_SPLASH_SCREEN = 1;
+ private static final int STARTING_TYPE_SNAPSHOT = 2;
+
+ TaskSnapshot mSnapshot;
+ int mPreferredType;
+
+ PreferredStartingTypeHelper(StartingWindowInfo taskInfo) {
+ final int parameter = taskInfo.startingWindowTypeParameter;
+ final boolean newTask = (parameter & TYPE_PARAMETER_NEW_TASK) != 0;
+ final boolean taskSwitch = (parameter & TYPE_PARAMETER_TASK_SWITCH) != 0;
+ final boolean processRunning = (parameter & TYPE_PARAMETER_PROCESS_RUNNING) != 0;
+ final boolean allowTaskSnapshot = (parameter & TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT) != 0;
+ final boolean activityCreated = (parameter & TYPE_PARAMETER_ACTIVITY_CREATED) != 0;
+ mPreferredType = preferredStartingWindowType(taskInfo, newTask, taskSwitch,
+ processRunning, allowTaskSnapshot, activityCreated);
+ }
+
+ // reference from ActivityRecord#getStartingWindowType
+ private int preferredStartingWindowType(StartingWindowInfo windowInfo,
+ boolean newTask, boolean taskSwitch, boolean processRunning,
+ boolean allowTaskSnapshot, boolean activityCreated) {
+ if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+ Slog.d(TAG, "preferredStartingWindowType newTask " + newTask
+ + " taskSwitch " + taskSwitch
+ + " processRunning " + processRunning
+ + " allowTaskSnapshot " + allowTaskSnapshot
+ + " activityCreated " + activityCreated);
+ }
+
+ if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
+ return STARTING_TYPE_SPLASH_SCREEN;
+ } else if (taskSwitch && allowTaskSnapshot) {
+ final TaskSnapshot snapshot = getTaskSnapshot(windowInfo.taskInfo.taskId);
+ if (isSnapshotCompatible(windowInfo, snapshot)) {
+ return STARTING_TYPE_SNAPSHOT;
+ }
+ if (windowInfo.taskInfo.topActivityType != ACTIVITY_TYPE_HOME) {
+ return STARTING_TYPE_SPLASH_SCREEN;
+ }
+ return STARTING_TYPE_NO;
+ } else {
+ return STARTING_TYPE_NO;
+ }
+ }
+
+ /**
+ * Returns {@code true} if the task snapshot is compatible with this activity (at least the
+ * rotation must be the same).
+ */
+ private boolean isSnapshotCompatible(StartingWindowInfo windowInfo, TaskSnapshot snapshot) {
+ if (snapshot == null) {
+ if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+ Slog.d(TAG, "isSnapshotCompatible no snapshot " + windowInfo.taskInfo.taskId);
+ }
+ return false;
+ }
+
+ final int taskRotation = windowInfo.taskInfo.configuration
+ .windowConfiguration.getRotation();
+ final int snapshotRotation = snapshot.getRotation();
+ if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+ Slog.d(TAG, "isSnapshotCompatible rotation " + taskRotation
+ + " snapshot " + snapshotRotation);
+ }
+ return taskRotation == snapshotRotation;
+ }
+
+ private TaskSnapshot getTaskSnapshot(int taskId) {
+ if (mSnapshot != null) {
+ return mSnapshot;
+ }
+ try {
+ mSnapshot = ActivityTaskManager.getService().getTaskSnapshot(taskId,
+ false/* isLowResolution */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to get snapshot for task: " + taskId + ", from: " + e);
+ return null;
+ }
+ return mSnapshot;
+ }
+ }
+
/**
* Called when a task need a starting window.
*/
- public void addStartingWindow(ActivityManager.RunningTaskInfo taskInfo, IBinder appToken) {
+ public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
+ final PreferredStartingTypeHelper helper =
+ new PreferredStartingTypeHelper(windowInfo);
+ final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo;
+ if (helper.mPreferredType == PreferredStartingTypeHelper.STARTING_TYPE_SPLASH_SCREEN) {
+ addSplashScreenStartingWindow(runningTaskInfo, appToken);
+ } else if (helper.mPreferredType == PreferredStartingTypeHelper.STARTING_TYPE_SNAPSHOT) {
+ final TaskSnapshot snapshot = helper.mSnapshot;
+ makeTaskSnapshotWindow(windowInfo, appToken, snapshot);
+ }
+ // If prefer don't show, then don't show!
+ }
+ private void addSplashScreenStartingWindow(RunningTaskInfo taskInfo, IBinder appToken) {
final ActivityInfo activityInfo = taskInfo.topActivityInfo;
+ if (activityInfo == null) {
+ return;
+ }
final int displayId = taskInfo.displayId;
if (activityInfo.packageName == null) {
return;
@@ -250,18 +360,34 @@
}
/**
+ * Called when a task need a snapshot starting window.
+ */
+ private void makeTaskSnapshotWindow(StartingWindowInfo startingWindowInfo,
+ IBinder appToken, TaskSnapshot snapshot) {
+ final int taskId = startingWindowInfo.taskInfo.taskId;
+ final TaskSnapshotWindow surface = TaskSnapshotWindow.create(startingWindowInfo, appToken,
+ snapshot, mMainExecutor, () -> removeWindowSynced(taskId) /* clearWindow */);
+ mMainExecutor.execute(() -> {
+ mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
+ final StartingWindowRecord tView =
+ new StartingWindowRecord(null/* decorView */, surface);
+ mStartingWindowRecords.put(taskId, tView);
+ });
+ }
+
+ /**
* Called when the content of a task is ready to show, starting window can be removed.
*/
- public void removeStartingWindow(ActivityManager.RunningTaskInfo taskInfo) {
- if (DEBUG_SPLASH_SCREEN) {
- Slog.d(TAG, "Task start finish, remove starting surface for task " + taskInfo.taskId);
+ public void removeStartingWindow(int taskId) {
+ if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+ Slog.d(TAG, "Task start finish, remove starting surface for task " + taskId);
}
- mHandler.post(() -> removeWindowSynced(taskInfo.taskId));
+ mMainExecutor.execute(() -> removeWindowSynced(taskId));
}
protected void postAddWindow(int taskId, IBinder appToken,
View view, WindowManager wm, WindowManager.LayoutParams params) {
- mHandler.post(() -> {
+ mMainExecutor.execute(() -> {
boolean shouldSaveView = true;
try {
wm.addView(view, params);
@@ -286,25 +412,32 @@
if (shouldSaveView) {
removeWindowSynced(taskId);
- mHandler.postDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
- final TaskScreenView tView = new TaskScreenView(view);
- mTaskScreenViews.put(taskId, tView);
+ mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
+ final StartingWindowRecord tView =
+ new StartingWindowRecord(view, null /* TaskSnapshotWindow */);
+ mStartingWindowRecords.put(taskId, tView);
}
});
}
protected void removeWindowSynced(int taskId) {
- final TaskScreenView preView = mTaskScreenViews.get(taskId);
- if (preView != null) {
- if (preView.mDecorView != null) {
+ final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
+ if (record != null) {
+ if (record.mDecorView != null) {
if (DEBUG_SPLASH_SCREEN) {
Slog.v(TAG, "Removing splash screen window for task: " + taskId);
}
- final WindowManager wm = preView.mDecorView.getContext()
+ final WindowManager wm = record.mDecorView.getContext()
.getSystemService(WindowManager.class);
- wm.removeView(preView.mDecorView);
+ wm.removeView(record.mDecorView);
}
- mTaskScreenViews.remove(taskId);
+ if (record.mTaskSnapshotWindow != null) {
+ if (DEBUG_TASK_SNAPSHOT) {
+ Slog.v(TAG, "Removing task snapshot window for " + taskId);
+ }
+ record.mTaskSnapshotWindow.remove(mMainExecutor);
+ }
+ mStartingWindowRecords.remove(taskId);
}
}
@@ -315,13 +448,15 @@
}
/**
- * Record the views in a starting window.
+ * Record the view or surface for a starting window.
*/
- private static class TaskScreenView {
+ private static class StartingWindowRecord {
private final View mDecorView;
+ private final TaskSnapshotWindow mTaskSnapshotWindow;
- TaskScreenView(View decorView) {
+ StartingWindowRecord(View decorView, TaskSnapshotWindow taskSnapshotWindow) {
mDecorView = decorView;
+ mTaskSnapshotWindow = taskSnapshotWindow;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
new file mode 100644
index 0000000..e66d85f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -0,0 +1,622 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.startingsurface;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.graphics.Color.WHITE;
+import static android.graphics.Color.alpha;
+import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
+import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+import static android.view.WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
+import static android.view.WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
+import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
+import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
+import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+
+import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
+import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
+import static com.android.internal.policy.DecorView.getNavigationBarRect;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityManager.TaskDescription;
+import android.app.ActivityThread;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.hardware.HardwareBuffer;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.MergedConfiguration;
+import android.util.Slog;
+import android.view.IWindowSession;
+import android.view.InputChannel;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+import android.window.ClientWindowFrames;
+import android.window.StartingWindowInfo;
+import android.window.TaskSnapshot;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.policy.DecorView;
+import com.android.internal.view.BaseIWindow;
+import com.android.wm.shell.common.ShellExecutor;
+
+/**
+ * This class represents a starting window that shows a snapshot.
+ *
+ * @hide
+ */
+public class TaskSnapshotWindow {
+
+ private static final long SIZE_MISMATCH_MINIMUM_TIME_MS = 450;
+
+ /**
+ * When creating the starting window, we use the exact same layout flags such that we end up
+ * with a window with the exact same dimensions etc. However, these flags are not used in layout
+ * and might cause other side effects so we exclude them.
+ */
+ static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE
+ | FLAG_NOT_TOUCHABLE
+ | FLAG_NOT_TOUCH_MODAL
+ | FLAG_ALT_FOCUSABLE_IM
+ | FLAG_NOT_FOCUSABLE
+ | FLAG_HARDWARE_ACCELERATED
+ | FLAG_IGNORE_CHEEK_PRESSES
+ | FLAG_LOCAL_FOCUS_MODE
+ | FLAG_SLIPPERY
+ | FLAG_WATCH_OUTSIDE_TOUCH
+ | FLAG_SPLIT_TOUCH
+ | FLAG_SCALED
+ | FLAG_SECURE;
+
+ private static final String TAG = StartingSurfaceDrawer.TAG;
+ private static final boolean DEBUG = StartingSurfaceDrawer.DEBUG_TASK_SNAPSHOT;
+ private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s";
+
+ //tmp vars for unused relayout params
+ private static final Point TMP_SURFACE_SIZE = new Point();
+
+ private final Window mWindow;
+ private final Surface mSurface;
+ private final Runnable mClearWindowHandler;
+ private SurfaceControl mSurfaceControl;
+ private SurfaceControl mChildSurfaceControl;
+ private final IWindowSession mSession;
+ private final Rect mTaskBounds;
+ private final Rect mFrame = new Rect();
+ private final Rect mSystemBarInsets = new Rect();
+ private TaskSnapshot mSnapshot;
+ private final RectF mTmpSnapshotSize = new RectF();
+ private final RectF mTmpDstFrame = new RectF();
+ private final CharSequence mTitle;
+ private boolean mHasDrawn;
+ private long mShownTime;
+ private boolean mSizeMismatch;
+ private final Paint mBackgroundPaint = new Paint();
+ private final int mActivityType;
+ private final int mStatusBarColor;
+ private final SystemBarBackgroundPainter mSystemBarBackgroundPainter;
+ private final int mOrientationOnCreation;
+ private final SurfaceControl.Transaction mTransaction;
+ private final Matrix mSnapshotMatrix = new Matrix();
+ private final float[] mTmpFloat9 = new float[9];
+
+ static TaskSnapshotWindow create(StartingWindowInfo info, IBinder appToken,
+ TaskSnapshot snapshot, ShellExecutor mainExecutor, Runnable clearWindowHandler) {
+ final ActivityManager.RunningTaskInfo runningTaskInfo = info.taskInfo;
+ final int taskId = runningTaskInfo.taskId;
+ if (DEBUG) {
+ Slog.d(TAG, "create taskSnapshot surface for task: " + taskId);
+ }
+
+ final WindowManager.LayoutParams attrs = info.topOpaqueWindowLayoutParams;
+ final WindowManager.LayoutParams mainWindowParams = info.mainWindowLayoutParams;
+ final InsetsState topWindowInsetsState = info.topOpaqueWindowInsetsState;
+ if (attrs == null || mainWindowParams == null || topWindowInsetsState == null) {
+ Slog.w(TAG, "unable to create taskSnapshot surface for task: " + taskId);
+ return null;
+ }
+ final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+
+ final int appearance = attrs.insetsFlags.appearance;
+ final int windowFlags = attrs.flags;
+ final int windowPrivateFlags = attrs.privateFlags;
+
+ layoutParams.packageName = mainWindowParams.packageName;
+ layoutParams.windowAnimations = mainWindowParams.windowAnimations;
+ layoutParams.dimAmount = mainWindowParams.dimAmount;
+ layoutParams.type = TYPE_APPLICATION_STARTING;
+ layoutParams.format = snapshot.getHardwareBuffer().getFormat();
+ layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES)
+ | FLAG_NOT_FOCUSABLE
+ | FLAG_NOT_TOUCHABLE;
+ // Setting as trusted overlay to let touches pass through. This is safe because this
+ // window is controlled by the system.
+ layoutParams.privateFlags = (windowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS)
+ | PRIVATE_FLAG_TRUSTED_OVERLAY;
+ layoutParams.token = appToken;
+ layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
+ layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
+ layoutParams.insetsFlags.appearance = appearance;
+ layoutParams.insetsFlags.behavior = attrs.insetsFlags.behavior;
+ layoutParams.layoutInDisplayCutoutMode = attrs.layoutInDisplayCutoutMode;
+ layoutParams.setFitInsetsTypes(attrs.getFitInsetsTypes());
+ layoutParams.setFitInsetsSides(attrs.getFitInsetsSides());
+ layoutParams.setFitInsetsIgnoringVisibility(attrs.isFitInsetsIgnoringVisibility());
+
+ layoutParams.setTitle(String.format(TITLE_FORMAT, taskId));
+
+ final Point taskSize = snapshot.getTaskSize();
+ final Rect taskBounds = new Rect(0, 0, taskSize.x, taskSize.y);
+ final int orientation = snapshot.getOrientation();
+
+ final int activityType = runningTaskInfo.topActivityType;
+ final int displayId = runningTaskInfo.displayId;
+
+ final IWindowSession session = WindowManagerGlobal.getWindowSession();
+ final SurfaceControl surfaceControl = new SurfaceControl();
+ final ClientWindowFrames tmpFrames = new ClientWindowFrames();
+
+ final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0];
+ final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
+
+ final TaskDescription taskDescription;
+ if (runningTaskInfo.taskDescription != null) {
+ taskDescription = runningTaskInfo.taskDescription;
+ } else {
+ taskDescription = new TaskDescription();
+ taskDescription.setBackgroundColor(WHITE);
+ }
+
+ final TaskSnapshotWindow snapshotSurface = new TaskSnapshotWindow(
+ surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, appearance,
+ windowFlags, windowPrivateFlags, taskBounds, orientation, activityType,
+ topWindowInsetsState, clearWindowHandler);
+ final Window window = snapshotSurface.mWindow;
+
+ final InsetsState mTmpInsetsState = new InsetsState();
+ final InputChannel tmpInputChannel = new InputChannel();
+ mainExecutor.execute(() -> {
+ try {
+ final int res = session.addToDisplay(window, layoutParams, View.GONE,
+ displayId, mTmpInsetsState, tmpFrames.frame,
+ tmpFrames.displayCutout, tmpInputChannel/* outInputChannel */,
+ mTmpInsetsState, mTempControls);
+ if (res < 0) {
+ Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
+ return;
+ }
+ } catch (RemoteException e) {
+ snapshotSurface.clearWindowSynced();
+ }
+ window.setOuter(snapshotSurface, mainExecutor);
+ try {
+ session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0, -1,
+ tmpFrames, tmpMergedConfiguration, surfaceControl, mTmpInsetsState,
+ mTempControls, TMP_SURFACE_SIZE);
+ } catch (RemoteException e) {
+ snapshotSurface.clearWindowSynced();
+ }
+
+ final Rect systemBarInsets = getSystemBarInsets(tmpFrames.frame, topWindowInsetsState);
+ snapshotSurface.setFrames(tmpFrames.frame, systemBarInsets);
+ snapshotSurface.drawSnapshot();
+ });
+ return snapshotSurface;
+ }
+
+ public TaskSnapshotWindow(SurfaceControl surfaceControl,
+ TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription,
+ int appearance, int windowFlags, int windowPrivateFlags, Rect taskBounds,
+ int currentOrientation, int activityType, InsetsState topWindowInsetsState,
+ Runnable clearWindowHandler) {
+ mSurface = new Surface();
+ mSession = WindowManagerGlobal.getWindowSession();
+ mWindow = new Window();
+ mWindow.setSession(mSession);
+ mSurfaceControl = surfaceControl;
+ mSnapshot = snapshot;
+ mTitle = title;
+ int backgroundColor = taskDescription.getBackgroundColor();
+ mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
+ mTaskBounds = taskBounds;
+ mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags,
+ windowPrivateFlags, appearance, taskDescription, 1f, topWindowInsetsState);
+ mStatusBarColor = taskDescription.getStatusBarColor();
+ mOrientationOnCreation = currentOrientation;
+ mActivityType = activityType;
+ mTransaction = new SurfaceControl.Transaction();
+ mClearWindowHandler = clearWindowHandler;
+ }
+
+ /**
+ * Ask system bar background painter to draw status bar background.
+ * @hide
+ */
+ public void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame) {
+ mSystemBarBackgroundPainter.drawStatusBarBackground(c, alreadyDrawnFrame,
+ mSystemBarBackgroundPainter.getStatusBarColorViewHeight());
+ }
+
+ /**
+ * Ask system bar background painter to draw navigation bar background.
+ * @hide
+ */
+ public void drawNavigationBarBackground(Canvas c) {
+ mSystemBarBackgroundPainter.drawNavigationBarBackground(c);
+ }
+
+ void remove(ShellExecutor mainExecutor) {
+ final long now = SystemClock.uptimeMillis();
+ if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS
+ // Show the latest content as soon as possible for unlocking to home.
+ && mActivityType != ACTIVITY_TYPE_HOME) {
+ final long delayTime = mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS - now;
+ mainExecutor.executeDelayed(() -> remove(mainExecutor), delayTime);
+ if (DEBUG) {
+ Slog.d(TAG, "Defer removing snapshot surface in " + delayTime);
+ }
+ return;
+ }
+ mainExecutor.execute(() -> {
+ try {
+ if (DEBUG) {
+ Slog.d(TAG, "Removing snapshot surface, mHasDrawn: " + mHasDrawn);
+ }
+ mSession.remove(mWindow);
+ } catch (RemoteException e) {
+ // nothing
+ }
+ });
+ }
+
+ /**
+ * Set frame size.
+ * @hide
+ */
+ public void setFrames(Rect frame, Rect systemBarInsets) {
+ mFrame.set(frame);
+ mSystemBarInsets.set(systemBarInsets);
+ final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer();
+ mSizeMismatch = (mFrame.width() != snapshot.getWidth()
+ || mFrame.height() != snapshot.getHeight());
+ mSystemBarBackgroundPainter.setInsets(systemBarInsets);
+ }
+
+ static Rect getSystemBarInsets(Rect frame, InsetsState state) {
+ return state.calculateInsets(frame, WindowInsets.Type.systemBars(),
+ false /* ignoreVisibility */);
+ }
+
+ private void drawSnapshot() {
+ mSurface.copyFrom(mSurfaceControl);
+ if (DEBUG) {
+ Slog.d(TAG, "Drawing snapshot surface sizeMismatch= " + mSizeMismatch);
+ }
+ if (mSizeMismatch) {
+ // The dimensions of the buffer and the window don't match, so attaching the buffer
+ // will fail. Better create a child window with the exact dimensions and fill the parent
+ // window with the background color!
+ drawSizeMismatchSnapshot();
+ } else {
+ drawSizeMatchSnapshot();
+ }
+ mShownTime = SystemClock.uptimeMillis();
+ mHasDrawn = true;
+ reportDrawn();
+
+ // In case window manager leaks us, make sure we don't retain the snapshot.
+ mSnapshot = null;
+ }
+
+ private void drawSizeMatchSnapshot() {
+ mSurface.attachAndQueueBufferWithColorSpace(mSnapshot.getHardwareBuffer(),
+ mSnapshot.getColorSpace());
+ mSurface.release();
+ }
+
+ private void drawSizeMismatchSnapshot() {
+ if (!mSurface.isValid()) {
+ throw new IllegalStateException("mSurface does not hold a valid surface.");
+ }
+ final HardwareBuffer buffer = mSnapshot.getHardwareBuffer();
+ final SurfaceSession session = new SurfaceSession();
+
+ // We consider nearly matched dimensions as there can be rounding errors and the user won't
+ // notice very minute differences from scaling one dimension more than the other
+ final boolean aspectRatioMismatch = Math.abs(
+ ((float) buffer.getWidth() / buffer.getHeight())
+ - ((float) mFrame.width() / mFrame.height())) > 0.01f;
+
+ // Keep a reference to it such that it doesn't get destroyed when finalized.
+ mChildSurfaceControl = new SurfaceControl.Builder(session)
+ .setName(mTitle + " - task-snapshot-surface")
+ .setBufferSize(buffer.getWidth(), buffer.getHeight())
+ .setFormat(buffer.getFormat())
+ .setParent(mSurfaceControl)
+ .setCallsite("TaskSnapshotWindow.drawSizeMismatchSnapshot")
+ .build();
+ Surface surface = new Surface();
+ surface.copyFrom(mChildSurfaceControl);
+
+ final Rect frame;
+ // 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);
+ mTmpSnapshotSize.set(crop);
+ mTmpDstFrame.set(frame);
+ } else {
+ frame = null;
+ mTmpSnapshotSize.set(0, 0, buffer.getWidth(), buffer.getHeight());
+ mTmpDstFrame.set(mFrame);
+ mTmpDstFrame.offsetTo(0, 0);
+ }
+
+ // Scale the mismatch dimensions to fill the task bounds
+ mSnapshotMatrix.setRectToRect(mTmpSnapshotSize, mTmpDstFrame, Matrix.ScaleToFit.FILL);
+ mTransaction.setMatrix(mChildSurfaceControl, mSnapshotMatrix, mTmpFloat9);
+
+ mTransaction.apply();
+ surface.attachAndQueueBufferWithColorSpace(buffer, mSnapshot.getColorSpace());
+ surface.release();
+
+ if (aspectRatioMismatch) {
+ final Canvas c = mSurface.lockCanvas(null);
+ drawBackgroundAndBars(c, frame);
+ mSurface.unlockCanvasAndPost(c);
+ mSurface.release();
+ }
+ }
+
+ /**
+ * Calculates the snapshot crop in snapshot coordinate space.
+ *
+ * @return crop rect in snapshot coordinate space.
+ */
+ public Rect calculateSnapshotCrop() {
+ final Rect rect = new Rect();
+ final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer();
+ rect.set(0, 0, snapshot.getWidth(), snapshot.getHeight());
+ final Rect insets = mSnapshot.getContentInsets();
+
+ final float scaleX = (float) snapshot.getWidth() / mSnapshot.getTaskSize().x;
+ final float scaleY = (float) snapshot.getHeight() / mSnapshot.getTaskSize().y;
+
+ // Let's remove all system decorations except the status bar, but only if the task is at the
+ // very top of the screen.
+ final boolean isTop = mTaskBounds.top == 0 && mFrame.top == 0;
+ rect.inset((int) (insets.left * scaleX),
+ isTop ? 0 : (int) (insets.top * scaleY),
+ (int) (insets.right * scaleX),
+ (int) (insets.bottom * scaleY));
+ return rect;
+ }
+
+ /**
+ * Calculates the snapshot frame in window coordinate space from crop.
+ *
+ * @param crop rect that is in snapshot coordinate space.
+ */
+ public Rect calculateSnapshotFrame(Rect crop) {
+ final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer();
+ final float scaleX = (float) snapshot.getWidth() / mSnapshot.getTaskSize().x;
+ final float scaleY = (float) snapshot.getHeight() / mSnapshot.getTaskSize().y;
+
+ // Rescale the frame from snapshot to window coordinate space
+ final Rect frame = new Rect(0, 0,
+ (int) (crop.width() / scaleX + 0.5f),
+ (int) (crop.height() / scaleY + 0.5f)
+ );
+
+ // However, we also need to make space for the navigation bar on the left side.
+ frame.offset(mSystemBarInsets.left, 0);
+ return frame;
+ }
+
+ /**
+ * Draw status bar and navigation bar background.
+ * @hide
+ */
+ public void drawBackgroundAndBars(Canvas c, Rect frame) {
+ final int statusBarHeight = mSystemBarBackgroundPainter.getStatusBarColorViewHeight();
+ final boolean fillHorizontally = c.getWidth() > frame.right;
+ final boolean fillVertically = c.getHeight() > frame.bottom;
+ if (fillHorizontally) {
+ c.drawRect(frame.right, alpha(mStatusBarColor) == 0xFF ? statusBarHeight : 0,
+ c.getWidth(), fillVertically
+ ? frame.bottom
+ : c.getHeight(),
+ mBackgroundPaint);
+ }
+ if (fillVertically) {
+ c.drawRect(0, frame.bottom, c.getWidth(), c.getHeight(), mBackgroundPaint);
+ }
+ mSystemBarBackgroundPainter.drawDecors(c, frame);
+ }
+
+ /**
+ * Clear window from drawer, must be post on main executor.
+ */
+ private void clearWindowSynced() {
+ if (mClearWindowHandler != null) {
+ mClearWindowHandler.run();
+ }
+ }
+
+ private void reportDrawn() {
+ try {
+ mSession.finishDrawing(mWindow, null /* postDrawTransaction */);
+ } catch (RemoteException e) {
+ clearWindowSynced();
+ }
+ }
+
+ static class Window extends BaseIWindow {
+ private TaskSnapshotWindow mOuter;
+ private ShellExecutor mMainExecutor;
+
+ public void setOuter(TaskSnapshotWindow outer, ShellExecutor mainExecutor) {
+ mOuter = outer;
+ mMainExecutor = mainExecutor;
+ }
+
+ @Override
+ public void resized(ClientWindowFrames frames, boolean reportDraw,
+ MergedConfiguration mergedConfiguration, boolean forceLayout,
+ boolean alwaysConsumeSystemBars, int displayId) {
+ if (mOuter != null) {
+ if (mergedConfiguration != null
+ && mOuter.mOrientationOnCreation
+ != mergedConfiguration.getMergedConfiguration().orientation) {
+ // The orientation of the screen is changing. We better remove the snapshot ASAP
+ // as we are going to wait on the new window in any case to unfreeze the screen,
+ // and the starting window is not needed anymore.
+ mMainExecutor.execute(() -> {
+ mOuter.clearWindowSynced();
+ });
+ } else if (reportDraw) {
+ mMainExecutor.execute(() -> {
+ if (mOuter.mHasDrawn) {
+ mOuter.reportDrawn();
+ }
+ });
+ }
+ }
+ }
+ }
+
+ /**
+ * Helper class to draw the background of the system bars in regions the task snapshot isn't
+ * filling the window.
+ */
+ static class SystemBarBackgroundPainter {
+ private final Paint mStatusBarPaint = new Paint();
+ private final Paint mNavigationBarPaint = new Paint();
+ private final int mStatusBarColor;
+ private final int mNavigationBarColor;
+ private final int mWindowFlags;
+ private final int mWindowPrivateFlags;
+ private final float mScale;
+ private final InsetsState mInsetsState;
+ private final Rect mSystemBarInsets = new Rect();
+
+ SystemBarBackgroundPainter(int windowFlags, int windowPrivateFlags, int appearance,
+ TaskDescription taskDescription, float scale, InsetsState insetsState) {
+ mWindowFlags = windowFlags;
+ mWindowPrivateFlags = windowPrivateFlags;
+ mScale = scale;
+ final Context context = ActivityThread.currentActivityThread().getSystemUiContext();
+ final int semiTransparent = context.getColor(
+ R.color.system_bar_background_semi_transparent);
+ mStatusBarColor = DecorView.calculateBarColor(windowFlags, FLAG_TRANSLUCENT_STATUS,
+ semiTransparent, taskDescription.getStatusBarColor(), appearance,
+ APPEARANCE_LIGHT_STATUS_BARS,
+ taskDescription.getEnsureStatusBarContrastWhenTransparent());
+ mNavigationBarColor = DecorView.calculateBarColor(windowFlags,
+ FLAG_TRANSLUCENT_NAVIGATION, semiTransparent,
+ taskDescription.getNavigationBarColor(), appearance,
+ APPEARANCE_LIGHT_NAVIGATION_BARS,
+ taskDescription.getEnsureNavigationBarContrastWhenTransparent()
+ && context.getResources().getBoolean(R.bool.config_navBarNeedsScrim));
+ mStatusBarPaint.setColor(mStatusBarColor);
+ mNavigationBarPaint.setColor(mNavigationBarColor);
+ mInsetsState = insetsState;
+ }
+
+ void setInsets(Rect systemBarInsets) {
+ mSystemBarInsets.set(systemBarInsets);
+ }
+
+ int getStatusBarColorViewHeight() {
+ final boolean forceBarBackground =
+ (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
+ if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
+ mInsetsState, mStatusBarColor, mWindowFlags, forceBarBackground)) {
+ return (int) (mSystemBarInsets.top * mScale);
+ } else {
+ return 0;
+ }
+ }
+
+ private boolean isNavigationBarColorViewVisible() {
+ final boolean forceBarBackground =
+ (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
+ return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
+ mInsetsState, mNavigationBarColor, mWindowFlags, forceBarBackground);
+ }
+
+ void drawDecors(Canvas c, @Nullable Rect alreadyDrawnFrame) {
+ drawStatusBarBackground(c, alreadyDrawnFrame, getStatusBarColorViewHeight());
+ drawNavigationBarBackground(c);
+ }
+
+ void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame,
+ int statusBarHeight) {
+ if (statusBarHeight > 0 && Color.alpha(mStatusBarColor) != 0
+ && (alreadyDrawnFrame == null || c.getWidth() > alreadyDrawnFrame.right)) {
+ final int rightInset = (int) (mSystemBarInsets.right * mScale);
+ final int left = alreadyDrawnFrame != null ? alreadyDrawnFrame.right : 0;
+ c.drawRect(left, 0, c.getWidth() - rightInset, statusBarHeight, mStatusBarPaint);
+ }
+ }
+
+ @VisibleForTesting
+ void drawNavigationBarBackground(Canvas c) {
+ final Rect navigationBarRect = new Rect();
+ getNavigationBarRect(c.getWidth(), c.getHeight(), mSystemBarInsets, navigationBarRect,
+ mScale);
+ final boolean visible = isNavigationBarColorViewVisible();
+ if (visible && Color.alpha(mNavigationBarColor) != 0 && !navigationBarRect.isEmpty()) {
+ c.drawRect(navigationBarRect, mNavigationBarPaint);
+ }
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
index c5b54bc..e3ac3f0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
@@ -17,6 +17,7 @@
package com.android.wm.shell.flicker
import android.graphics.Region
+import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
import com.android.server.wm.flicker.dsl.EventLogAssertion
import com.android.server.wm.flicker.dsl.LayersAssertion
import com.android.server.wm.flicker.helpers.WindowUtils
@@ -52,6 +53,30 @@
}
@JvmOverloads
+fun LayersAssertion.dockedStackDividerBecomesVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("dividerLayerBecomesVisible") {
+ this.hidesLayer(DOCKED_STACK_DIVIDER)
+ .then()
+ .showsLayer(DOCKED_STACK_DIVIDER)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.dockedStackDividerBecomesInvisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("dividerLayerBecomesInvisible") {
+ this.showsLayer(DOCKED_STACK_DIVIDER)
+ .then()
+ .hidesLayer(DOCKED_STACK_DIVIDER)
+ }
+}
+
+@JvmOverloads
fun LayersAssertion.dockedStackDividerIsInvisible(
bugId: Int = 0,
enabled: Boolean = bugId == 0
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
index d580104..c546a4d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
@@ -20,7 +20,6 @@
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import com.android.server.wm.flicker.helpers.FIND_TIMEOUT
-import com.android.server.wm.flicker.helpers.waitForIME
import com.android.wm.shell.flicker.TEST_APP_IME_ACTIVITY_LABEL
import com.android.wm.shell.flicker.testapp.Components
import org.junit.Assert
@@ -39,14 +38,9 @@
Assert.assertNotNull("Text field not found, this usually happens when the device " +
"was left in an unknown state (e.g. in split screen)", editText)
editText.click()
- if (!uiDevice.waitForIME()) {
- Assert.fail("IME did not appear")
- }
}
fun closeIME() {
uiDevice.pressBack()
- // Using only the AccessibilityInfo it is not possible to identify if the IME is active
- uiDevice.waitForIdle(1000)
}
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt
index 02f6f8c..b33fa55 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt
@@ -27,9 +27,9 @@
import com.android.server.wm.flicker.helpers.isInSplitScreen
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.openQuickstep
+import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
-import com.android.wm.shell.flicker.dockedStackDividerIsVisible
import com.android.wm.shell.flicker.helpers.SplitScreenHelper.Companion.TEST_REPETITIONS
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
@@ -38,6 +38,9 @@
import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible
import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisible
import org.junit.Assert
+import com.android.wm.shell.flicker.dockedStackDividerBecomesVisible
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -46,7 +49,7 @@
/**
* Test SplitScreen launch.
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenTest`
+ * To run this test: `atest WMShellFlickerTests:EnterLegacySplitScreenTest`
*/
@Presubmit
@RequiresDevice
@@ -56,6 +59,8 @@
rotationName: String,
rotation: Int
) : SplitScreenTestBase(rotationName, rotation) {
+ private val letterBox = "Letterbox"
+
private val splitScreenSetup: FlickerBuilder
get() = FlickerBuilder(instrumentation).apply {
val testLaunchActivity = "launch_splitScreen_test_activity"
@@ -65,6 +70,7 @@
setup {
eachRun {
uiDevice.wakeUpAndGoToHomeScreen()
+ uiDevice.openQuickStepAndClearRecentAppsFromOverview()
}
}
teardown {
@@ -85,6 +91,7 @@
windowManagerTrace {
navBarWindowIsAlwaysVisible()
statusBarWindowIsAlwaysVisible()
+ visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(launcherPackageName))
}
}
}
@@ -103,9 +110,12 @@
}
assertions {
layersTrace {
- dockedStackDividerIsVisible()
dockedStackPrimaryBoundsIsVisible(
rotation, splitScreenApp.defaultWindowName, 169271943)
+ dockedStackDividerBecomesVisible()
+ visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(launcherPackageName, splitScreenApp.defaultWindowName)
+ )
}
windowManagerTrace {
end {
@@ -132,11 +142,15 @@
}
assertions {
layersTrace {
- dockedStackDividerIsVisible()
dockedStackPrimaryBoundsIsVisible(
rotation, splitScreenApp.defaultWindowName, 169271943)
dockedStackSecondaryBoundsIsVisible(
rotation, secondaryApp.defaultWindowName, 169271943)
+ dockedStackDividerBecomesVisible()
+ visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(launcherPackageName, splitScreenApp.defaultWindowName,
+ secondaryApp.defaultWindowName)
+ )
}
windowManagerTrace {
end {
@@ -166,6 +180,9 @@
assertions {
layersTrace {
dockedStackDividerIsInvisible()
+ visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(launcherPackageName, nonResizeableApp.defaultWindowName)
+ )
}
windowManagerTrace {
end {
@@ -197,6 +214,10 @@
val displayBounds = WindowUtils.getDisplayBounds(rotation)
this.hasVisibleRegion(nonResizeableApp.defaultWindowName, displayBounds)
}
+ visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(launcherPackageName, splitScreenApp.defaultWindowName,
+ nonResizeableApp.defaultWindowName, letterBox)
+ )
}
windowManagerTrace {
end {
@@ -229,6 +250,10 @@
val displayBounds = WindowUtils.getDisplayBounds(rotation)
this.hasVisibleRegion(nonResizeableApp.defaultWindowName, displayBounds)
}
+ visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(launcherPackageName, splitScreenApp.defaultWindowName,
+ nonResizeableApp.defaultWindowName, letterBox)
+ )
}
windowManagerTrace {
end {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottomTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottomTest.kt
new file mode 100644
index 0000000..573ffc6
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottomTest.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.legacysplitscreen
+
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.helpers.buildTestTag
+import com.android.server.wm.flicker.helpers.exitSplitScreen
+import com.android.server.wm.flicker.helpers.exitSplitScreenFromBottom
+import com.android.server.wm.flicker.helpers.isInSplitScreen
+import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.repetitions
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test open app to split screen.
+ * To run this test: `atest WMShellFlickerTests:ExitLegacySplitScreenFromBottomTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class ExitLegacySplitScreenFromBottomTest(
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> {
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = StandardAppHelper(instrumentation,
+ "com.android.wm.shell.flicker.testapp", "SimpleApp")
+
+ // b/161435597 causes the test not to work on 90 degrees
+ return FlickerTestRunnerFactory(instrumentation, listOf(Surface.ROTATION_0))
+ .buildTest { configuration ->
+ withTestName {
+ buildTestTag("exitSplitScreenFromBottom", testApp,
+ configuration)
+ }
+ repeat { configuration.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ }
+ eachRun {
+ testApp.open()
+ device.launchSplitScreen()
+ device.waitForIdle()
+ this.setRotation(configuration.endRotation)
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit()
+ }
+ test {
+ if (device.isInSplitScreen()) {
+ device.exitSplitScreen()
+ }
+ }
+ }
+ transitions {
+ device.exitSplitScreenFromBottom()
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenTest.kt
index 33306bf..c51c73a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenTest.kt
@@ -21,16 +21,22 @@
import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.layerBecomesInvisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.dsl.runWithFlicker
import com.android.server.wm.flicker.helpers.exitSplitScreen
import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
import com.android.server.wm.flicker.helpers.resizeSplitScreen
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper.Companion.TEST_REPETITIONS
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
+import com.android.wm.shell.flicker.helpers.SplitScreenHelper.Companion.TEST_REPETITIONS
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -39,7 +45,7 @@
/**
* Test exit SplitScreen mode.
- * To run this test: `atest WMShellFlickerTests:ExitSplitScreenTest`
+ * To run this test: `atest WMShellFlickerTests:ExitLegacySplitScreenTest`
*/
@Presubmit
@RequiresDevice
@@ -58,10 +64,9 @@
setup {
eachRun {
uiDevice.wakeUpAndGoToHomeScreen()
- secondaryApp.open()
- uiDevice.pressHome()
- splitScreenApp.open()
- uiDevice.pressHome()
+ uiDevice.openQuickStepAndClearRecentAppsFromOverview()
+ secondaryApp.launchViaIntent()
+ splitScreenApp.launchViaIntent()
uiDevice.launchSplitScreen()
}
}
@@ -71,6 +76,15 @@
secondaryApp.exit()
}
}
+ assertions {
+ windowManagerTrace {
+ visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
+ layersTrace {
+ visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(launcherPackageName))
+ }
+ }
}
@Test
@@ -87,6 +101,7 @@
assertions {
layersTrace {
dockedStackDividerIsInvisible()
+ layerBecomesInvisible(splitScreenApp.defaultWindowName)
}
windowManagerTrace {
navBarWindowIsAlwaysVisible()
@@ -137,4 +152,4 @@
return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
}
}
-}
\ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncherTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncherTest.kt
index cc02aa3..629c71f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncherTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncherTest.kt
@@ -17,10 +17,10 @@
package com.android.wm.shell.flicker.legacysplitscreen
import android.platform.test.annotations.Presubmit
+import android.support.test.launcherhelper.LauncherStrategyFactory
import android.view.Surface
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
import com.android.server.wm.flicker.Flicker
import com.android.server.wm.flicker.FlickerTestRunner
import com.android.server.wm.flicker.FlickerTestRunnerFactory
@@ -31,16 +31,21 @@
import com.android.server.wm.flicker.helpers.exitSplitScreen
import com.android.server.wm.flicker.helpers.isInSplitScreen
import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.layerBecomesInvisible
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.wm.shell.flicker.dockedStackDividerBecomesInvisible
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -48,7 +53,7 @@
/**
* Test open app to split screen.
- * To run this test: `atest WMShellFlickerTests:SplitScreenToLauncherTest`
+ * To run this test: `atest WMShellFlickerTests:LegacySplitScreenToLauncherTest`
*/
@Presubmit
@RequiresDevice
@@ -63,6 +68,8 @@
@JvmStatic
fun getParams(): Collection<Array<Any>> {
val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val launcherPackageName = LauncherStrategyFactory.getInstance(instrumentation)
+ .launcherStrategy.supportedLauncherPackage
val testApp = StandardAppHelper(instrumentation,
"com.android.wm.shell.flicker.testapp", "SimpleApp")
@@ -76,6 +83,7 @@
setup {
test {
device.wakeUpAndGoToHomeScreen()
+ device.openQuickStepAndClearRecentAppsFromOverview()
}
eachRun {
testApp.open()
@@ -101,6 +109,7 @@
windowManagerTrace {
navBarWindowIsAlwaysVisible()
statusBarWindowIsAlwaysVisible()
+ visibleWindowsShownMoreThanOneConsecutiveEntry()
}
layersTrace {
@@ -109,19 +118,13 @@
noUncoveredRegions(configuration.endRotation)
navBarLayerRotatesAndScales(configuration.endRotation)
statusBarLayerRotatesScales(configuration.endRotation)
+ visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(launcherPackageName))
// b/161435597 causes the test not to work on 90 degrees
- all("dividerLayerBecomesInvisible") {
- this.showsLayer(DOCKED_STACK_DIVIDER)
- .then()
- .hidesLayer(DOCKED_STACK_DIVIDER)
- }
+ dockedStackDividerBecomesInvisible()
- all("appLayerBecomesInvisible") {
- this.showsLayer(testApp.getPackage())
- .then()
- .hidesLayer(testApp.getPackage())
- }
+ layerBecomesInvisible(testApp.getPackage())
}
eventLog {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreenTest.kt
index bb80726..af03869 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreenTest.kt
@@ -17,30 +17,36 @@
package com.android.wm.shell.flicker.legacysplitscreen
import android.platform.test.annotations.Presubmit
+import android.support.test.launcherhelper.LauncherStrategyFactory
import android.view.Surface
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
import com.android.server.wm.flicker.Flicker
import com.android.server.wm.flicker.FlickerTestRunner
import com.android.server.wm.flicker.FlickerTestRunnerFactory
-import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.focusChanges
import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.exitSplitScreen
import com.android.server.wm.flicker.helpers.isInSplitScreen
import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.appWindowBecomesVisible
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.layerBecomesVisible
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.wm.shell.flicker.dockedStackDividerBecomesVisible
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -48,7 +54,7 @@
/**
* Test open app to split screen.
- * To run this test: `atest WMShellFlickerTests:OpenAppToSplitScreenTest`
+ * To run this test: `atest WMShellFlickerTests:OpenAppToLegacySplitScreenTest`
*/
@Presubmit
@RequiresDevice
@@ -63,6 +69,8 @@
@JvmStatic
fun getParams(): Collection<Array<Any>> {
val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val launcherPackageName = LauncherStrategyFactory.getInstance(instrumentation)
+ .launcherStrategy.supportedLauncherPackage
val testApp = StandardAppHelper(instrumentation,
"com.android.wm.shell.flicker.testapp", "SimpleApp")
@@ -76,9 +84,11 @@
setup {
test {
device.wakeUpAndGoToHomeScreen()
+ device.openQuickStepAndClearRecentAppsFromOverview()
}
eachRun {
testApp.open()
+ device.pressHome()
this.setRotation(configuration.endRotation)
}
}
@@ -99,6 +109,9 @@
windowManagerTrace {
navBarWindowIsAlwaysVisible()
statusBarWindowIsAlwaysVisible()
+ visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+ appWindowBecomesVisible(testApp.getPackage())
}
layersTrace {
@@ -108,12 +121,11 @@
navBarLayerRotatesAndScales(configuration.endRotation,
bugId = 140855415)
statusBarLayerRotatesScales(configuration.endRotation)
+ visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(launcherPackageName))
- all("dividerLayerBecomesVisible") {
- this.hidesLayer(DOCKED_STACK_DIVIDER)
- .then()
- .showsLayer(DOCKED_STACK_DIVIDER)
- }
+ dockedStackDividerBecomesVisible()
+ layerBecomesVisible(testApp.getPackage())
}
eventLog {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreenTest.kt
index e3beb41..391cb2a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreenTest.kt
@@ -47,6 +47,8 @@
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
@@ -55,7 +57,7 @@
/**
* Test split screen resizing window transitions.
- * To run this test: `atest WMShellFlickerTests:ResizeSplitScreenTest`
+ * To run this test: `atest WMShellFlickerTests:ResizeLegacySplitScreenTest`
*
* Currently it runs only in 0 degrees because of b/156100803
*/
@@ -131,6 +133,7 @@
windowManagerTrace {
navBarWindowIsAlwaysVisible()
statusBarWindowIsAlwaysVisible()
+ visibleWindowsShownMoreThanOneConsecutiveEntry()
all("topAppWindowIsAlwaysVisible", bugId = 156223549) {
this.showsAppWindow(sSimpleActivity)
@@ -147,6 +150,7 @@
noUncoveredRegions(configuration.endRotation)
navBarLayerRotatesAndScales(configuration.endRotation)
statusBarLayerRotatesScales(configuration.endRotation)
+ visibleLayersShownMoreThanOneConsecutiveEntry()
all("topAppLayerIsAlwaysVisible") {
this.showsLayer(sSimpleActivity)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppTest.kt
index ae2200c..923f2a4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppTest.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.helpers.exitSplitScreen
import com.android.server.wm.flicker.helpers.isInSplitScreen
import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
@@ -56,7 +57,8 @@
}
setup {
test {
- device.wakeUpAndGoToHomeScreen()
+ uiDevice.wakeUpAndGoToHomeScreen()
+ uiDevice.openQuickStepAndClearRecentAppsFromOverview()
}
}
teardown {
@@ -81,7 +83,7 @@
}
transitions {
splitScreenApp.launchViaIntent()
- device.launchSplitScreen()
+ uiDevice.launchSplitScreen()
setRotation(rotation)
}
assertions {
@@ -114,7 +116,7 @@
transitions {
splitScreenApp.launchViaIntent()
setRotation(rotation)
- device.launchSplitScreen()
+ uiDevice.launchSplitScreen()
}
assertions {
layersTrace {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppTest.kt
index a1b44f0..4578f68 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppTest.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.helpers.exitSplitScreen
import com.android.server.wm.flicker.helpers.isInSplitScreen
import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
@@ -57,7 +58,8 @@
}
setup {
test {
- device.wakeUpAndGoToHomeScreen()
+ uiDevice.wakeUpAndGoToHomeScreen()
+ uiDevice.openQuickStepAndClearRecentAppsFromOverview()
}
}
teardown {
@@ -83,7 +85,7 @@
transitions {
secondaryApp.launchViaIntent()
splitScreenApp.launchViaIntent()
- device.launchSplitScreen()
+ uiDevice.launchSplitScreen()
splitScreenApp.reopenAppFromOverview()
setRotation(rotation)
}
@@ -121,7 +123,7 @@
secondaryApp.launchViaIntent()
splitScreenApp.launchViaIntent()
setRotation(rotation)
- device.launchSplitScreen()
+ uiDevice.launchSplitScreen()
splitScreenApp.reopenAppFromOverview()
}
assertions {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/SplitScreenTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/SplitScreenTestBase.kt
index a2e325e..a536ec8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/SplitScreenTestBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/SplitScreenTestBase.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.legacysplitscreen
+import android.support.test.launcherhelper.LauncherStrategyFactory
import com.android.wm.shell.flicker.NonRotationTestBase
import com.android.wm.shell.flicker.TEST_APP_NONRESIZEABLE_LABEL
import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_PRIMARY_LABEL
@@ -36,4 +37,6 @@
protected val nonResizeableApp = SplitScreenHelper(instrumentation,
TEST_APP_NONRESIZEABLE_LABEL,
Components.NonResizeableActivity())
+ protected val launcherPackageName = LauncherStrategyFactory.getInstance(instrumentation)
+ .launcherStrategy.supportedLauncherPackage
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
index 6b44ce6..866d654 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
@@ -25,8 +25,10 @@
import com.android.server.wm.flicker.helpers.closePipWindow
import com.android.server.wm.flicker.helpers.hasPipWindow
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import com.android.wm.shell.flicker.IME_WINDOW_NAME
import com.android.wm.shell.flicker.helpers.ImeAppHelper
+import com.android.wm.shell.flicker.testapp.Components
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -46,6 +48,8 @@
rotation: Int
) : PipTestBase(rotationName, rotation) {
private val keyboardApp = ImeAppHelper(instrumentation)
+ private val keyboardComponent = Components.ImeActivity().componentName
+ private val helper = WindowManagerStateHelper()
private val keyboardScenario: FlickerBuilder
get() = FlickerBuilder(instrumentation).apply {
@@ -64,6 +68,8 @@
// UiAutomator doesn't support to launch the multiple Activities in a task.
// So use launchActivity() for the Keyboard Activity.
keyboardApp.launchViaIntent()
+ helper.waitForAppTransitionIdle()
+ helper.waitForFullScreenApp(keyboardComponent)
}
}
teardown {
@@ -88,9 +94,11 @@
transitions {
// open the soft keyboard
keyboardApp.openIME()
+ helper.waitImeWindowShown()
// then close it again
keyboardApp.closeIME()
+ helper.waitImeWindowGone()
}
assertions {
windowManagerTrace {
@@ -112,11 +120,13 @@
transitions {
// open the soft keyboard
keyboardApp.openIME()
+ helper.waitImeWindowShown()
}
teardown {
eachRun {
// close the keyboard
keyboardApp.closeIME()
+ helper.waitImeWindowGone()
}
}
assertions {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
index 81cdbf0..9eae179 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
@@ -41,7 +41,7 @@
/**
* Test Pip with split-screen.
- * To run this test: `atest WMShellFlickerTests:PipSplitScreenTest`
+ * To run this test: `atest WMShellFlickerTests:PipLegacySplitScreenTest`
*/
@RequiresDevice
@RunWith(Parameterized::class)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
index 7f280cd..d30fa38 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
@@ -197,6 +197,11 @@
}
@Override
+ public SurfaceControl.Transaction setFrameTimelineVsync(long frameTimelineVsyncId) {
+ return this;
+ }
+
+ @Override
public void apply() {}
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
index 8ba301a..dea24d3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
@@ -31,14 +31,13 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.util.function.TriConsumer;
import com.android.wm.shell.ShellTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.function.BiConsumer;
-
/**
* Tests for {@link PipBoundsState}.
*/
@@ -117,23 +116,33 @@
@Test
public void testSetShelfVisibility_changed_callbackInvoked() {
- final BiConsumer<Boolean, Integer> callback = mock(BiConsumer.class);
+ final TriConsumer<Boolean, Integer, Boolean> callback = mock(TriConsumer.class);
mPipBoundsState.setOnShelfVisibilityChangeCallback(callback);
mPipBoundsState.setShelfVisibility(true, 100);
- verify(callback).accept(true, 100);
+ verify(callback).accept(true, 100, true);
+ }
+
+ @Test
+ public void testSetShelfVisibility_changedWithoutUpdateMovBounds_callbackInvoked() {
+ final TriConsumer<Boolean, Integer, Boolean> callback = mock(TriConsumer.class);
+ mPipBoundsState.setOnShelfVisibilityChangeCallback(callback);
+
+ mPipBoundsState.setShelfVisibility(true, 100, false);
+
+ verify(callback).accept(true, 100, false);
}
@Test
public void testSetShelfVisibility_notChanged_callbackNotInvoked() {
- final BiConsumer<Boolean, Integer> callback = mock(BiConsumer.class);
+ final TriConsumer<Boolean, Integer, Boolean> callback = mock(TriConsumer.class);
mPipBoundsState.setShelfVisibility(true, 100);
mPipBoundsState.setOnShelfVisibilityChangeCallback(callback);
mPipBoundsState.setShelfVisibility(true, 100);
- verify(callback, never()).accept(true, 100);
+ verify(callback, never()).accept(true, 100, true);
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index f5628ab..07115c2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -41,11 +41,14 @@
import android.view.View;
import android.view.WindowManager;
import android.view.WindowMetrics;
+import android.window.StartingWindowInfo;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.wm.shell.common.HandlerExecutor;
+import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.startingsurface.StartingSurfaceDrawer;
import org.junit.Before;
@@ -70,8 +73,8 @@
static final class TestStartingSurfaceDrawer extends StartingSurfaceDrawer{
int mAddWindowForTask = 0;
- TestStartingSurfaceDrawer(Context context) {
- super(context);
+ TestStartingSurfaceDrawer(Context context, ShellExecutor executor) {
+ super(context, executor);
}
@Override
@@ -109,36 +112,38 @@
doReturn(metrics).when(mMockWindowManager).getMaximumWindowMetrics();
doNothing().when(mMockWindowManager).addView(any(), any());
- mStartingSurfaceDrawer = spy(new TestStartingSurfaceDrawer(context));
+ mStartingSurfaceDrawer = spy(new TestStartingSurfaceDrawer(context,
+ new HandlerExecutor(new Handler(Looper.getMainLooper()))));
}
@Test
public void testAddSplashScreenSurface() {
final int taskId = 1;
final Handler mainLoop = new Handler(Looper.getMainLooper());
- final ActivityManager.RunningTaskInfo taskInfo =
- createTaskInfo(taskId, WINDOWING_MODE_FULLSCREEN);
- mStartingSurfaceDrawer.addStartingWindow(taskInfo, mBinder);
+ final StartingWindowInfo windowInfo =
+ createWindowInfo(taskId, WINDOWING_MODE_FULLSCREEN);
+ mStartingSurfaceDrawer.addStartingWindow(windowInfo, mBinder);
waitHandlerIdle(mainLoop);
verify(mStartingSurfaceDrawer).postAddWindow(eq(taskId), eq(mBinder), any(), any(), any());
assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, taskId);
- mStartingSurfaceDrawer.removeStartingWindow(taskInfo);
+ mStartingSurfaceDrawer.removeStartingWindow(windowInfo.taskInfo.taskId);
waitHandlerIdle(mainLoop);
verify(mStartingSurfaceDrawer).removeWindowSynced(eq(taskId));
assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, 0);
}
- private ActivityManager.RunningTaskInfo createTaskInfo(int taskId, int windowingMode) {
- ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
+ private StartingWindowInfo createWindowInfo(int taskId, int windowingMode) {
+ StartingWindowInfo windowInfo = new StartingWindowInfo();
final ActivityInfo info = new ActivityInfo();
info.applicationInfo = new ApplicationInfo();
info.packageName = "test";
info.theme = android.R.style.Theme;
+ final ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
taskInfo.topActivityInfo = info;
taskInfo.taskId = taskId;
- taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
- return taskInfo;
+ windowInfo.taskInfo = taskInfo;
+ return windowInfo;
}
private static void waitHandlerIdle(Handler handler) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
new file mode 100644
index 0000000..94af329
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2017 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 unittest.src.com.android.wm.shell.startingsurface;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+
+import android.app.ActivityManager.TaskDescription;
+import android.content.ComponentName;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorSpace;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
+import android.view.InsetsState;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.window.TaskSnapshot;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.startingsurface.TaskSnapshotWindow;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test class for {@link TaskSnapshotWindow}.
+ *
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TaskSnapshotWindowTest {
+
+ private TaskSnapshotWindow mWindow;
+
+ private void setupSurface(int width, int height) {
+ setupSurface(width, height, new Rect(), 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+ new Rect(0, 0, width, height));
+ }
+
+ private void setupSurface(int width, int height, Rect contentInsets, int sysuiVis,
+ int windowFlags, Rect taskBounds) {
+ // Previously when constructing TaskSnapshots for this test, scale was 1.0f, so to mimic
+ // this behavior set the taskSize to be the same as the taskBounds width and height. The
+ // taskBounds passed here are assumed to be the same task bounds as when the snapshot was
+ // taken. We assume there is no aspect ratio mismatch between the screenshot and the
+ // taskBounds
+ assertEquals(width, taskBounds.width());
+ assertEquals(height, taskBounds.height());
+ Point taskSize = new Point(taskBounds.width(), taskBounds.height());
+
+ final TaskSnapshot snapshot = createTaskSnapshot(width, height, taskSize, contentInsets);
+ mWindow = new TaskSnapshotWindow(new SurfaceControl(), snapshot, "Test",
+ createTaskDescription(Color.WHITE, Color.RED, Color.BLUE),
+ 0 /* appearance */, windowFlags /* windowFlags */, 0 /* privateWindowFlags */,
+ taskBounds, ORIENTATION_PORTRAIT, ACTIVITY_TYPE_STANDARD, new InsetsState(),
+ null /* clearWindow */);
+ }
+
+ private TaskSnapshot createTaskSnapshot(int width, int height, Point taskSize,
+ Rect contentInsets) {
+ final HardwareBuffer buffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888,
+ 1, HardwareBuffer.USAGE_CPU_READ_RARELY);
+ return new TaskSnapshot(
+ System.currentTimeMillis(),
+ new ComponentName("", ""), buffer,
+ ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
+ Surface.ROTATION_0, taskSize, contentInsets, false,
+ true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN,
+ 0 /* systemUiVisibility */, false /* isTranslucent */);
+ }
+
+ private static TaskDescription createTaskDescription(int background, int statusBar,
+ int navigationBar) {
+ final TaskDescription td = new TaskDescription();
+ td.setBackgroundColor(background);
+ td.setStatusBarColor(statusBar);
+ td.setNavigationBarColor(navigationBar);
+ return td;
+ }
+
+ @Test
+ public void fillEmptyBackground_fillHorizontally() {
+ setupSurface(200, 100);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(200);
+ when(mockCanvas.getHeight()).thenReturn(100);
+ mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 200));
+ verify(mockCanvas).drawRect(eq(100.0f), eq(0.0f), eq(200.0f), eq(100.0f), any());
+ }
+
+ @Test
+ public void fillEmptyBackground_fillVertically() {
+ setupSurface(100, 200);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(100);
+ when(mockCanvas.getHeight()).thenReturn(200);
+ mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 100));
+ verify(mockCanvas).drawRect(eq(0.0f), eq(100.0f), eq(100.0f), eq(200.0f), any());
+ }
+
+ @Test
+ public void fillEmptyBackground_fillBoth() {
+ setupSurface(200, 200);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(200);
+ when(mockCanvas.getHeight()).thenReturn(200);
+ mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100));
+ verify(mockCanvas).drawRect(eq(100.0f), eq(0.0f), eq(200.0f), eq(100.0f), any());
+ verify(mockCanvas).drawRect(eq(0.0f), eq(100.0f), eq(200.0f), eq(200.0f), any());
+ }
+
+ @Test
+ public void fillEmptyBackground_dontFill_sameSize() {
+ setupSurface(100, 100);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(100);
+ when(mockCanvas.getHeight()).thenReturn(100);
+ mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100));
+ verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void fillEmptyBackground_dontFill_bitmapLarger() {
+ setupSurface(100, 100);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(100);
+ when(mockCanvas.getHeight()).thenReturn(100);
+ mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 200));
+ verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testCalculateSnapshotCrop() {
+ setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 0, 100, 100));
+ assertEquals(new Rect(0, 0, 100, 90), mWindow.calculateSnapshotCrop());
+ }
+
+ @Test
+ public void testCalculateSnapshotCrop_taskNotOnTop() {
+ setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 50, 100, 150));
+ assertEquals(new Rect(0, 10, 100, 90), mWindow.calculateSnapshotCrop());
+ }
+
+ @Test
+ public void testCalculateSnapshotCrop_navBarLeft() {
+ setupSurface(100, 100, new Rect(10, 10, 0, 0), 0, 0, new Rect(0, 0, 100, 100));
+ assertEquals(new Rect(10, 0, 100, 100), mWindow.calculateSnapshotCrop());
+ }
+
+ @Test
+ public void testCalculateSnapshotCrop_navBarRight() {
+ setupSurface(100, 100, new Rect(0, 10, 10, 0), 0, 0, new Rect(0, 0, 100, 100));
+ assertEquals(new Rect(0, 0, 90, 100), mWindow.calculateSnapshotCrop());
+ }
+
+ @Test
+ public void testCalculateSnapshotCrop_waterfall() {
+ setupSurface(100, 100, new Rect(5, 10, 5, 10), 0, 0, new Rect(0, 0, 100, 100));
+ assertEquals(new Rect(5, 0, 95, 90), mWindow.calculateSnapshotCrop());
+ }
+
+ @Test
+ public void testCalculateSnapshotFrame() {
+ setupSurface(100, 100);
+ final Rect insets = new Rect(0, 10, 0, 10);
+ mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+ assertEquals(new Rect(0, 0, 100, 80),
+ mWindow.calculateSnapshotFrame(new Rect(0, 10, 100, 90)));
+ }
+
+ @Test
+ public void testCalculateSnapshotFrame_navBarLeft() {
+ setupSurface(100, 100);
+ final Rect insets = new Rect(10, 10, 0, 0);
+ mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+ assertEquals(new Rect(10, 0, 100, 90),
+ mWindow.calculateSnapshotFrame(new Rect(10, 10, 100, 100)));
+ }
+
+ @Test
+ public void testCalculateSnapshotFrame_waterfall() {
+ setupSurface(100, 100, new Rect(5, 10, 5, 10), 0, 0, new Rect(0, 0, 100, 100));
+ final Rect insets = new Rect(0, 10, 0, 10);
+ mWindow.setFrames(new Rect(5, 0, 95, 100), insets);
+ assertEquals(new Rect(0, 0, 90, 90),
+ mWindow.calculateSnapshotFrame(new Rect(5, 0, 95, 90)));
+ }
+
+ @Test
+ public void testDrawStatusBarBackground() {
+ setupSurface(100, 100);
+ final Rect insets = new Rect(0, 10, 10, 0);
+ mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(100);
+ when(mockCanvas.getHeight()).thenReturn(100);
+ mWindow.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 50, 100));
+ verify(mockCanvas).drawRect(eq(50.0f), eq(0.0f), eq(90.0f), eq(10.0f), any());
+ }
+
+ @Test
+ public void testDrawStatusBarBackground_nullFrame() {
+ setupSurface(100, 100);
+ final Rect insets = new Rect(0, 10, 10, 0);
+ mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(100);
+ when(mockCanvas.getHeight()).thenReturn(100);
+ mWindow.drawStatusBarBackground(mockCanvas, null);
+ verify(mockCanvas).drawRect(eq(0.0f), eq(0.0f), eq(90.0f), eq(10.0f), any());
+ }
+
+ @Test
+ public void testDrawStatusBarBackground_nope() {
+ setupSurface(100, 100);
+ final Rect insets = new Rect(0, 10, 10, 0);
+ mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(100);
+ when(mockCanvas.getHeight()).thenReturn(100);
+ mWindow.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 100, 100));
+ verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testDrawNavigationBarBackground() {
+ final Rect insets = new Rect(0, 10, 0, 10);
+ setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+ new Rect(0, 0, 100, 100));
+ mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(100);
+ when(mockCanvas.getHeight()).thenReturn(100);
+ mWindow.drawNavigationBarBackground(mockCanvas);
+ verify(mockCanvas).drawRect(eq(new Rect(0, 90, 100, 100)), any());
+ }
+
+ @Test
+ public void testDrawNavigationBarBackground_left() {
+ final Rect insets = new Rect(10, 10, 0, 0);
+ setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+ new Rect(0, 0, 100, 100));
+ mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(100);
+ when(mockCanvas.getHeight()).thenReturn(100);
+ mWindow.drawNavigationBarBackground(mockCanvas);
+ verify(mockCanvas).drawRect(eq(new Rect(0, 0, 10, 100)), any());
+ }
+
+ @Test
+ public void testDrawNavigationBarBackground_right() {
+ final Rect insets = new Rect(0, 10, 10, 0);
+ setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+ new Rect(0, 0, 100, 100));
+ mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(100);
+ when(mockCanvas.getHeight()).thenReturn(100);
+ mWindow.drawNavigationBarBackground(mockCanvas);
+ verify(mockCanvas).drawRect(eq(new Rect(90, 0, 100, 100)), any());
+ }
+}
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index a545b3d..bec80a7 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -670,7 +670,7 @@
}
auto entry_flags = type_spec->GetFlagsForEntryIndex(entry_idx);
- if (UNLIKELY(!entry_flags)) {
+ if (UNLIKELY(!entry_flags.has_value())) {
return base::unexpected(entry_flags.error());
}
type_flags |= entry_flags.value();
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 4010e4e..bce70e2 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -897,12 +897,12 @@
// Decode the UTF-16 length. This is not used if we're not
// converting to UTF-16 from UTF-8.
const base::expected<size_t, IOError> u16len = decodeLength(&str);
- if (UNLIKELY(!u16len)) {
+ if (UNLIKELY(!u16len.has_value())) {
return base::unexpected(u16len.error());
}
const base::expected<size_t, IOError> u8len = decodeLength(&str);
- if (UNLIKELY(!u8len)) {
+ if (UNLIKELY(!u8len.has_value())) {
return base::unexpected(u8len.error());
}
diff --git a/libs/androidfw/ResourceUtils.cpp b/libs/androidfw/ResourceUtils.cpp
index a34aa72..87fb2c0 100644
--- a/libs/androidfw/ResourceUtils.cpp
+++ b/libs/androidfw/ResourceUtils.cpp
@@ -56,7 +56,8 @@
.package_len = package_name.size(),
};
- if (base::expected<StringPiece, NullOrIOError> type_str = type_string_ref.string8()) {
+ if (base::expected<StringPiece, NullOrIOError> type_str = type_string_ref.string8();
+ type_str.ok()) {
name.type = type_str->data();
name.type_len = type_str->size();
} else if (UNLIKELY(IsIOError(type_str))) {
@@ -64,7 +65,8 @@
}
if (name.type == nullptr) {
- if (base::expected<StringPiece16, NullOrIOError> type16_str = type_string_ref.string16()) {
+ if (base::expected<StringPiece16, NullOrIOError> type16_str = type_string_ref.string16();
+ type16_str.ok()) {
name.type16 = type16_str->data();
name.type_len = type16_str->size();
} else if (!type16_str.has_value()) {
@@ -72,7 +74,8 @@
}
}
- if (base::expected<StringPiece, NullOrIOError> entry_str = entry_string_ref.string8()) {
+ if (base::expected<StringPiece, NullOrIOError> entry_str = entry_string_ref.string8();
+ entry_str.ok()) {
name.entry = entry_str->data();
name.entry_len = entry_str->size();
} else if (UNLIKELY(IsIOError(entry_str))) {
@@ -80,7 +83,8 @@
}
if (name.entry == nullptr) {
- if (base::expected<StringPiece16, NullOrIOError> entry16_str = entry_string_ref.string16()) {
+ if (base::expected<StringPiece16, NullOrIOError> entry16_str = entry_string_ref.string16();
+ entry16_str.ok()) {
name.entry16 = entry16_str->data();
name.entry_len = entry16_str->size();
} else if (!entry16_str.has_value()) {
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index bfbdc5c..c6c9e9d 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -19,8 +19,6 @@
#include <private/hwui/DrawGlInfo.h>
#include "FunctorDrawable.h"
#include "GrBackendSurface.h"
-#include "GrRenderTarget.h"
-#include "GrRenderTargetContext.h"
#include "RenderNode.h"
#include "SkAndroidFrameworkUtils.h"
#include "SkClipStack.h"
@@ -40,19 +38,13 @@
}
static void GetFboDetails(SkCanvas* canvas, GLuint* outFboID, SkISize* outFboSize) {
- GrRenderTargetContext* renderTargetContext =
- canvas->internal_private_accessTopLayerRenderTargetContext();
- LOG_ALWAYS_FATAL_IF(!renderTargetContext, "Failed to retrieve GrRenderTargetContext");
-
- GrRenderTarget* renderTarget = renderTargetContext->accessRenderTarget();
- LOG_ALWAYS_FATAL_IF(!renderTarget, "accessRenderTarget failed");
-
+ GrBackendRenderTarget renderTarget = canvas->topLayerBackendRenderTarget();
GrGLFramebufferInfo fboInfo;
- LOG_ALWAYS_FATAL_IF(!renderTarget->getBackendRenderTarget().getGLFramebufferInfo(&fboInfo),
+ LOG_ALWAYS_FATAL_IF(!renderTarget.getGLFramebufferInfo(&fboInfo),
"getGLFrameBufferInfo failed");
*outFboID = fboInfo.fFBOID;
- *outFboSize = SkISize::Make(renderTargetContext->width(), renderTargetContext->height());
+ *outFboSize = renderTarget.dimensions();
}
void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
@@ -75,7 +67,7 @@
SkISize fboSize;
GetFboDetails(canvas, &fboID, &fboSize);
- SkIRect surfaceBounds = canvas->internal_private_getTopLayerBounds();
+ SkIRect surfaceBounds = canvas->topLayerBounds();
SkIRect clipBounds = canvas->getDeviceClipBounds();
SkM44 mat4(canvas->getLocalToDevice());
SkRegion clipRegion;
diff --git a/location/java/android/location/GnssMeasurementRequest.aidl b/location/java/android/location/GnssMeasurementRequest.aidl
new file mode 100644
index 0000000..7e50728
--- /dev/null
+++ b/location/java/android/location/GnssMeasurementRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location;
+
+parcelable GnssMeasurementRequest;
diff --git a/location/java/android/location/GnssMeasurementRequest.java b/location/java/android/location/GnssMeasurementRequest.java
new file mode 100644
index 0000000..613f591
--- /dev/null
+++ b/location/java/android/location/GnssMeasurementRequest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class contains extra parameters to pass in a GNSS measurement request.
+ */
+public final class GnssMeasurementRequest implements Parcelable {
+ private final boolean mFullTracking;
+
+ /**
+ * Creates a {@link GnssMeasurementRequest} with a full list of parameters.
+ */
+ private GnssMeasurementRequest(boolean fullTracking) {
+ mFullTracking = fullTracking;
+ }
+
+ /**
+ * Represents whether to enable full GNSS tracking.
+ *
+ * <p>If true, GNSS chipset switches off duty cycling. In such a mode, no clock
+ * discontinuities are expected, and when supported, carrier phase should be continuous in
+ * good signal conditions. All non-blocklisted, healthy constellations, satellites and
+ * frequency bands that the chipset supports must be reported in this mode. The GNSS chipset
+ * will consume more power in full tracking mode than in duty cycling mode. If false, GNSS
+ * chipset optimizes power via duty cycling, constellations and frequency limits, etc.
+ *
+ * <p>Full GNSS tracking mode affects GnssMeasurement and other GNSS functionalities
+ * including GNSS location.
+ */
+ public boolean isFullTracking() {
+ return mFullTracking;
+ }
+
+ @NonNull
+ public static final Creator<GnssMeasurementRequest> CREATOR =
+ new Creator<GnssMeasurementRequest>() {
+ @Override
+ @NonNull
+ public GnssMeasurementRequest createFromParcel(@NonNull Parcel parcel) {
+ return new GnssMeasurementRequest(parcel.readBoolean());
+ }
+
+ @Override
+ public GnssMeasurementRequest[] newArray(int i) {
+ return new GnssMeasurementRequest[i];
+ }
+ };
+
+ @Override
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
+ parcel.writeBoolean(mFullTracking);
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ StringBuilder s = new StringBuilder();
+ s.append("GnssMeasurementRequest[");
+ if (mFullTracking) {
+ s.append("FullTracking");
+ }
+ s.append(']');
+ return s.toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (!(obj instanceof GnssMeasurementRequest)) return false;
+
+ GnssMeasurementRequest other = (GnssMeasurementRequest) obj;
+ if (mFullTracking != other.mFullTracking) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return mFullTracking ? 1 : 0;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Builder for {@link GnssMeasurementRequest} */
+ public static final class Builder {
+ private boolean mFullTracking;
+
+ /**
+ * Constructs a {@link Builder} instance.
+ */
+ public Builder() {
+ }
+
+ /**
+ * Constructs a {@link Builder} instance by copying a {@link GnssMeasurementRequest}.
+ */
+ public Builder(@NonNull GnssMeasurementRequest request) {
+ mFullTracking = request.isFullTracking();
+ }
+
+ /**
+ * Set the value of whether to enable full GNSS tracking, which is false by default.
+ *
+ * <p>If true, GNSS chipset switches off duty cycling. In such a mode, no clock
+ * discontinuities are expected, and when supported, carrier phase should be continuous in
+ * good signal conditions. All non-blocklisted, healthy constellations, satellites and
+ * frequency bands that the chipset supports must be reported in this mode. The GNSS chipset
+ * will consume more power in full tracking mode than in duty cycling mode. If false,
+ * GNSS chipset optimizes power via duty cycling, constellations and frequency limits, etc.
+ *
+ * <p>Full GNSS tracking mode affects GnssMeasurement and other GNSS functionalities
+ * including GNSS location.
+ *
+ * <p>Full tracking requests always override non-full tracking requests. If any full
+ * tracking request occurs, all listeners on the device will receive full tracking GNSS
+ * measurements.
+ */
+ @NonNull public Builder setFullTracking(boolean value) {
+ mFullTracking = value;
+ return this;
+ }
+
+ /** Builds a {@link GnssMeasurementRequest} instance as specified by this builder. */
+ @NonNull
+ public GnssMeasurementRequest build() {
+ return new GnssMeasurementRequest(mFullTracking);
+ }
+ }
+}
diff --git a/location/java/android/location/GnssRequest.java b/location/java/android/location/GnssRequest.java
index 5fc9161..9c9766f 100644
--- a/location/java/android/location/GnssRequest.java
+++ b/location/java/android/location/GnssRequest.java
@@ -45,11 +45,23 @@
* frequency bands that the chipset supports must be reported in this mode. The GNSS chipset
* is allowed to consume more power in this mode. If false, GNSS chipset optimizes power via
* duty cycling, constellations and frequency limits, etc.
+ *
+ * <p>Full GNSS tracking mode affects GnssMeasurement and other GNSS functionalities
+ * including GNSS location.
*/
public boolean isFullTracking() {
return mFullTracking;
}
+ /**
+ * Converts the {@link GnssRequest} into a {@link GnssMeasurementRequest}.
+ * @hide
+ */
+ @NonNull
+ public GnssMeasurementRequest toGnssMeasurementRequest() {
+ return new GnssMeasurementRequest.Builder().setFullTracking(isFullTracking()).build();
+ }
+
@NonNull
public static final Creator<GnssRequest> CREATOR =
new Creator<GnssRequest>() {
@@ -131,6 +143,9 @@
* is allowed to consume more power in this mode. If false, GNSS chipset optimizes power via
* duty cycling, constellations and frequency limits, etc.
*
+ * <p>Full GNSS tracking mode affects GnssMeasurement and other GNSS functionalities
+ * including GNSS location.
+ *
* <p>Full tracking requests always override non-full tracking requests. If any full
* tracking request occurs, all listeners on the device will receive full tracking GNSS
* measurements.
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 92e2136..a666eb4 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -22,7 +22,7 @@
import android.location.GeocoderParams;
import android.location.Geofence;
import android.location.GnssMeasurementCorrections;
-import android.location.GnssRequest;
+import android.location.GnssMeasurementRequest;
import android.location.IGeocodeListener;
import android.location.IGnssAntennaInfoListener;
import android.location.IGnssMeasurementsListener;
@@ -78,7 +78,7 @@
void registerGnssStatusCallback(in IGnssStatusListener callback, String packageName, String attributionTag);
void unregisterGnssStatusCallback(in IGnssStatusListener callback);
- void addGnssMeasurementsListener(in GnssRequest request, in IGnssMeasurementsListener listener, String packageName, String attributionTag);
+ void addGnssMeasurementsListener(in GnssMeasurementRequest request, in IGnssMeasurementsListener listener, String packageName, String attributionTag);
void removeGnssMeasurementsListener(in IGnssMeasurementsListener listener);
void injectGnssMeasurementCorrections(in GnssMeasurementCorrections corrections);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 914beaf..ecdba1f 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -2371,7 +2371,7 @@
handler = new Handler();
}
- return registerGnssMeasurementsCallback(new GnssRequest.Builder().build(),
+ return registerGnssMeasurementsCallback(new GnssMeasurementRequest.Builder().build(),
new HandlerExecutor(handler), callback);
}
@@ -2390,8 +2390,8 @@
public boolean registerGnssMeasurementsCallback(
@NonNull @CallbackExecutor Executor executor,
@NonNull GnssMeasurementsEvent.Callback callback) {
- return registerGnssMeasurementsCallback(new GnssRequest.Builder().build(), executor,
- callback);
+ return registerGnssMeasurementsCallback(new GnssMeasurementRequest.Builder().build(),
+ executor, callback);
}
/**
@@ -2408,14 +2408,42 @@
* @throws IllegalArgumentException if callback is null
* @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
* @hide
+ * @deprecated Use {@link #registerGnssMeasurementsCallback(GnssMeasurementRequest, Executor,
+ * GnssMeasurementsEvent.Callback)} instead.
*/
+ @Deprecated
@SystemApi
- @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, LOCATION_HARDWARE})
+ @RequiresPermission(ACCESS_FINE_LOCATION)
public boolean registerGnssMeasurementsCallback(
@NonNull GnssRequest request,
@NonNull @CallbackExecutor Executor executor,
@NonNull GnssMeasurementsEvent.Callback callback) {
Preconditions.checkArgument(request != null, "invalid null request");
+ getGnssMeasurementsTransportMultiplexer().addListener(request.toGnssMeasurementRequest(),
+ callback, executor);
+ return true;
+ }
+
+ /**
+ * Registers a GNSS measurement callback.
+ *
+ * @param request extra parameters to pass to GNSS measurement provider. For example, if {@link
+ * GnssMeasurementRequest#isFullTracking()} is true, GNSS chipset switches off
+ * duty cycling.
+ * @param executor the executor that the callback runs on
+ * @param callback a {@link GnssMeasurementsEvent.Callback} object to register.
+ * @return {@code true} always if the callback was added successfully, {@code false} otherwise.
+ * @throws IllegalArgumentException if request is null
+ * @throws IllegalArgumentException if executor is null
+ * @throws IllegalArgumentException if callback is null
+ * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
+ */
+ @RequiresPermission(ACCESS_FINE_LOCATION)
+ public boolean registerGnssMeasurementsCallback(
+ @NonNull GnssMeasurementRequest request,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull GnssMeasurementsEvent.Callback callback) {
+ Preconditions.checkArgument(request != null, "invalid null request");
getGnssMeasurementsTransportMultiplexer().addListener(request, callback, executor);
return true;
}
@@ -2907,14 +2935,14 @@
}
private class GnssMeasurementsTransportMultiplexer extends
- ListenerTransportMultiplexer<GnssRequest, GnssMeasurementsEvent.Callback> {
+ ListenerTransportMultiplexer<GnssMeasurementRequest, GnssMeasurementsEvent.Callback> {
private @Nullable IGnssMeasurementsListener mListenerTransport;
GnssMeasurementsTransportMultiplexer() {}
@Override
- protected void registerWithServer(GnssRequest request) throws RemoteException {
+ protected void registerWithServer(GnssMeasurementRequest request) throws RemoteException {
IGnssMeasurementsListener transport = mListenerTransport;
if (transport == null) {
transport = new GnssMeasurementsListener();
@@ -2937,9 +2965,10 @@
}
@Override
- protected GnssRequest mergeRequests(Collection<GnssRequest> requests) {
- GnssRequest.Builder builder = new GnssRequest.Builder();
- for (GnssRequest request : requests) {
+ protected GnssMeasurementRequest mergeRequests(
+ Collection<GnssMeasurementRequest> requests) {
+ GnssMeasurementRequest.Builder builder = new GnssMeasurementRequest.Builder();
+ for (GnssMeasurementRequest request : requests) {
if (request.isFullTracking()) {
builder.setFullTracking(true);
break;
diff --git a/media/java/android/media/AudioDeviceAttributes.java b/media/java/android/media/AudioDeviceAttributes.java
index 6c8b500..7caac89 100644
--- a/media/java/android/media/AudioDeviceAttributes.java
+++ b/media/java/android/media/AudioDeviceAttributes.java
@@ -120,7 +120,13 @@
mAddress = address;
}
- /*package*/ AudioDeviceAttributes(int nativeType, @NonNull String address) {
+ /**
+ * @hide
+ * Constructor from internal device type and address
+ * @param type the internal device type, as defined in {@link AudioSystem}
+ * @param address the address of the device, or an empty string for devices without one
+ */
+ public AudioDeviceAttributes(int nativeType, @NonNull String address) {
mRole = (nativeType & AudioSystem.DEVICE_BIT_IN) != 0 ? ROLE_INPUT : ROLE_OUTPUT;
mType = AudioDeviceInfo.convertInternalDeviceToDeviceType(nativeType);
mAddress = address;
@@ -191,10 +197,8 @@
public String toString() {
return new String("AudioDeviceAttributes:"
+ " role:" + roleToString(mRole)
- + " type:" + (mRole == ROLE_OUTPUT ? AudioSystem.getOutputDeviceName(
- AudioDeviceInfo.convertDeviceTypeToInternalDevice(mType))
- : AudioSystem.getInputDeviceName(
- AudioDeviceInfo.convertDeviceTypeToInternalDevice(mType)))
+ + " type:" + (mRole == ROLE_OUTPUT ? AudioSystem.getOutputDeviceName(mNativeType)
+ : AudioSystem.getInputDeviceName(mNativeType))
+ " addr:" + mAddress);
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index d9cfb63..367b784 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -6183,6 +6183,29 @@
}
/**
+ * Returns an {@link AudioDeviceInfo} corresponding to the specified {@link AudioPort} ID.
+ * @param portId The audio port ID to look up for.
+ * @param flags A set of bitflags specifying the criteria to test.
+ * @see #GET_DEVICES_OUTPUTS
+ * @see #GET_DEVICES_INPUTS
+ * @see #GET_DEVICES_ALL
+ * @return An AudioDeviceInfo or null if no device with matching port ID is found.
+ * @hide
+ */
+ public static AudioDeviceInfo getDeviceForPortId(int portId, int flags) {
+ if (portId == 0) {
+ return null;
+ }
+ AudioDeviceInfo[] devices = getDevicesStatic(flags);
+ for (AudioDeviceInfo device : devices) {
+ if (device.getId() == portId) {
+ return device;
+ }
+ }
+ return null;
+ }
+
+ /**
* Registers an {@link AudioDeviceCallback} object to receive notifications of changes
* to the set of connected audio devices.
* @param callback The {@link AudioDeviceCallback} object to receive connect/disconnect
@@ -6869,6 +6892,297 @@
return hwSyncId;
}
+ /**
+ * Selects the audio device that should be used for communication use cases, for instance voice
+ * or video calls. This method can be used by voice or video chat applications to select a
+ * different audio device than the one selected by default by the platform.
+ * <p>The device selection is expressed as an {@link AudioDeviceInfo}, of role sink
+ * ({@link AudioDeviceInfo#isSink()} is <code>true</code>) and of one of the following types:
+ * <ul>
+ * <li> {@link AudioDeviceInfo#TYPE_BUILTIN_EARPIECE}
+ * <li> {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}
+ * <li> {@link AudioDeviceInfo#TYPE_WIRED_HEADSET}
+ * <li> {@link AudioDeviceInfo#TYPE_BLUETOOTH_SCO}
+ * <li> {@link AudioDeviceInfo#TYPE_USB_HEADSET}
+ * <li> {@link AudioDeviceInfo#TYPE_BLE_HEADSET}
+ * </ul>
+ * The selection is active as long as the requesting application lives, until
+ * {@link #clearDeviceForCommunication} is called or until the device is disconnected.
+ * It is therefore important for applications to clear the request when a call ends or the
+ * application is paused.
+ * <p>In case of simultaneous requests by multiple applications the priority is given to the
+ * application currently controlling the audio mode (see {@link #setMode(int)}). This is the
+ * latest application having selected mode {@link #MODE_IN_COMMUNICATION} or mode
+ * {@link #MODE_IN_CALL}. Note that <code>MODE_IN_CALL</code> can only be selected by the main
+ * telephony application with permission
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE}.
+ * <p> If the requested devices is not currently available, the request will be rejected and
+ * the method will return false.
+ * <p>This API replaces the following deprecated APIs:
+ * <ul>
+ * <li> {@link #startBluetoothSco()}
+ * <li> {@link #stopBluetoothSco()}
+ * <li> {@link #setSpeakerphoneOn(boolean)}
+ * </ul>
+ * <h4>Example</h4>
+ * <p>The example below shows how to enable and disable speakerphone mode.
+ * <pre class="prettyprint">
+ * // Get an AudioManager instance
+ * AudioManager audioManager = Context.getSystemService(AudioManager.class);
+ * try {
+ * AudioDeviceInfo speakerDevice = null;
+ * AudioDeviceInfo[] devices = audioManager.getDevices(GET_DEVICES_OUTPUTS);
+ * for (AudioDeviceInfo device : devices) {
+ * if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
+ * speakerDevice = device;
+ * break;
+ * }
+ * }
+ * if (speakerDevice != null) {
+ * // Turn speakerphone ON.
+ * boolean result = audioManager.setDeviceForCommunication(speakerDevice);
+ * if (!result) {
+ * // Handle error.
+ * }
+ * // Turn speakerphone OFF.
+ * audioManager.clearDeviceForCommunication();
+ * }
+ * } catch (IllegalArgumentException e) {
+ * // Handle exception.
+ * }
+ * </pre>
+ * @param device the requested audio device.
+ * @return <code>true</code> if the request was accepted, <code>false</code> otherwise.
+ * @throws IllegalArgumentException If an invalid device is specified.
+ */
+ public boolean setDeviceForCommunication(@NonNull AudioDeviceInfo device) {
+ Objects.requireNonNull(device);
+ try {
+ if (device.getId() == 0) {
+ throw new IllegalArgumentException("In valid device: " + device);
+ }
+ return getService().setDeviceForCommunication(mICallBack, device.getId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Cancels previous communication device selection made with
+ * {@link #setDeviceForCommunication(AudioDeviceInfo)}.
+ */
+ public void clearDeviceForCommunication() {
+ try {
+ getService().setDeviceForCommunication(mICallBack, 0);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns currently selected audio device for communication.
+ * <p>This API replaces the following deprecated APIs:
+ * <ul>
+ * <li> {@link #isBluetoothScoOn()}
+ * <li> {@link #isSpeakerphoneOn()}
+ * </ul>
+ * @return an {@link AudioDeviceInfo} indicating which audio device is
+ * currently selected or communication use cases or null if default selection
+ * is used.
+ */
+ @Nullable
+ public AudioDeviceInfo getDeviceForCommunication() {
+ try {
+ return getDeviceForPortId(
+ getService().getDeviceForCommunication(), GET_DEVICES_OUTPUTS);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type provided.
+ * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
+ * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
+ * The method will return null if no device of the provided type is connected.
+ * If more than one device of the provided type is connected, an object corresponding to the
+ * first device encountered in the enumeration list will be returned.
+ * @param deviceType The device device for which an <code>AudioDeviceInfo</code>
+ * object is queried.
+ * @return An AudioDeviceInfo object or null if no device with the requested type is connected.
+ * @throws IllegalArgumentException If an invalid device type is specified.
+ */
+ @TestApi
+ @Nullable
+ public static AudioDeviceInfo getDeviceInfoFromType(
+ @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
+ AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_OUTPUTS);
+ for (AudioDeviceInfo device : devices) {
+ if (device.getType() == deviceType) {
+ return device;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Listener registered by client to be notified upon communication audio device change.
+ * See {@link #setDeviceForCommunication(AudioDeviceInfo)}.
+ */
+ public interface OnCommunicationDeviceChangedListener {
+ /**
+ * Callback method called upon communication audio device change.
+ * @param device the audio device selected for communication use cases
+ */
+ void onCommunicationDeviceChanged(@Nullable AudioDeviceInfo device);
+ }
+
+ /**
+ * Adds a listener for being notified of changes to the communication audio device.
+ * See {@link #setDeviceForCommunication(AudioDeviceInfo)}.
+ * @param executor
+ * @param listener
+ */
+ public void addOnCommunicationDeviceChangedListener(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnCommunicationDeviceChangedListener listener) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(listener);
+ synchronized (mCommDevListenerLock) {
+ if (hasCommDevListener(listener)) {
+ throw new IllegalArgumentException(
+ "attempt to call addOnCommunicationDeviceChangedListener() "
+ + "on a previously registered listener");
+ }
+ // lazy initialization of the list of strategy-preferred device listener
+ if (mCommDevListeners == null) {
+ mCommDevListeners = new ArrayList<>();
+ }
+ final int oldCbCount = mCommDevListeners.size();
+ mCommDevListeners.add(new CommDevListenerInfo(listener, executor));
+ if (oldCbCount == 0 && mCommDevListeners.size() > 0) {
+ // register binder for callbacks
+ if (mCommDevDispatcherStub == null) {
+ mCommDevDispatcherStub = new CommunicationDeviceDispatcherStub();
+ }
+ try {
+ getService().registerCommunicationDeviceDispatcher(mCommDevDispatcherStub);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes a previously added listener of changes to the communication audio device.
+ * See {@link #setDeviceForCommunication(AudioDeviceInfo)}.
+ * @param listener
+ */
+ public void removeOnCommunicationDeviceChangedListener(
+ @NonNull OnCommunicationDeviceChangedListener listener) {
+ Objects.requireNonNull(listener);
+ synchronized (mCommDevListenerLock) {
+ if (!removeCommDevListener(listener)) {
+ throw new IllegalArgumentException(
+ "attempt to call removeOnCommunicationDeviceChangedListener() "
+ + "on an unregistered listener");
+ }
+ if (mCommDevListeners.size() == 0) {
+ // unregister binder for callbacks
+ try {
+ getService().unregisterCommunicationDeviceDispatcher(
+ mCommDevDispatcherStub);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } finally {
+ mCommDevDispatcherStub = null;
+ mCommDevListeners = null;
+ }
+ }
+ }
+ }
+
+ private final Object mCommDevListenerLock = new Object();
+ /**
+ * List of listeners for preferred device for strategy and their associated Executor.
+ * List is lazy-initialized on first registration
+ */
+ @GuardedBy("mCommDevListenerLock")
+ private @Nullable ArrayList<CommDevListenerInfo> mCommDevListeners;
+
+ private static class CommDevListenerInfo {
+ final @NonNull OnCommunicationDeviceChangedListener mListener;
+ final @NonNull Executor mExecutor;
+
+ CommDevListenerInfo(OnCommunicationDeviceChangedListener listener, Executor exe) {
+ mListener = listener;
+ mExecutor = exe;
+ }
+ }
+
+ @GuardedBy("mCommDevListenerLock")
+ private CommunicationDeviceDispatcherStub mCommDevDispatcherStub;
+
+ private final class CommunicationDeviceDispatcherStub
+ extends ICommunicationDeviceDispatcher.Stub {
+
+ @Override
+ public void dispatchCommunicationDeviceChanged(int portId) {
+ // make a shallow copy of listeners so callback is not executed under lock
+ final ArrayList<CommDevListenerInfo> commDevListeners;
+ synchronized (mCommDevListenerLock) {
+ if (mCommDevListeners == null || mCommDevListeners.size() == 0) {
+ return;
+ }
+ commDevListeners = (ArrayList<CommDevListenerInfo>) mCommDevListeners.clone();
+ }
+ AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ for (CommDevListenerInfo info : commDevListeners) {
+ info.mExecutor.execute(() ->
+ info.mListener.onCommunicationDeviceChanged(device));
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ @GuardedBy("mCommDevListenerLock")
+ private @Nullable CommDevListenerInfo getCommDevListenerInfo(
+ OnCommunicationDeviceChangedListener listener) {
+ if (mCommDevListeners == null) {
+ return null;
+ }
+ for (CommDevListenerInfo info : mCommDevListeners) {
+ if (info.mListener == listener) {
+ return info;
+ }
+ }
+ return null;
+ }
+
+ @GuardedBy("mCommDevListenerLock")
+ private boolean hasCommDevListener(OnCommunicationDeviceChangedListener listener) {
+ return getCommDevListenerInfo(listener) != null;
+ }
+
+ @GuardedBy("mCommDevListenerLock")
+ /**
+ * @return true if the listener was removed from the list
+ */
+ private boolean removeCommDevListener(OnCommunicationDeviceChangedListener listener) {
+ final CommDevListenerInfo infoToRemove = getCommDevListenerInfo(listener);
+ if (infoToRemove != null) {
+ mCommDevListeners.remove(infoToRemove);
+ return true;
+ }
+ return false;
+ }
+
//---------------------------------------------------------
// Inner classes
//--------------------
diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java
index b9f449c..17305a5 100644
--- a/media/java/android/media/AudioPlaybackConfiguration.java
+++ b/media/java/android/media/AudioPlaybackConfiguration.java
@@ -21,7 +21,6 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Binder;
import android.os.IBinder;
@@ -48,8 +47,6 @@
public static final int PLAYER_PIID_INVALID = -1;
/** @hide */
public static final int PLAYER_UPID_INVALID = -1;
- /** @hide */
- public static final int PLAYER_DEVICEID_INVALID = 0;
// information about the implementation
/**
@@ -161,11 +158,6 @@
*/
@SystemApi
public static final int PLAYER_STATE_STOPPED = 4;
- /**
- * @hide
- * The state used to update device id, does not actually change the state of the player
- */
- public static final int PLAYER_UPDATE_DEVICE_ID = 5;
/** @hide */
@IntDef({
@@ -174,8 +166,7 @@
PLAYER_STATE_IDLE,
PLAYER_STATE_STARTED,
PLAYER_STATE_PAUSED,
- PLAYER_STATE_STOPPED,
- PLAYER_UPDATE_DEVICE_ID
+ PLAYER_STATE_STOPPED
})
@Retention(RetentionPolicy.SOURCE)
public @interface PlayerState {}
@@ -193,8 +184,6 @@
private int mPlayerState;
private AudioAttributes mPlayerAttr; // never null
- private int mDeviceId;
-
/**
* Never use without initializing parameters afterwards
*/
@@ -212,7 +201,6 @@
mPlayerType = pic.mPlayerType;
mClientUid = uid;
mClientPid = pid;
- mDeviceId = PLAYER_DEVICEID_INVALID;
mPlayerState = PLAYER_STATE_IDLE;
mPlayerAttr = pic.mAttributes;
if ((sPlayerDeathMonitor != null) && (pic.mIPlayer != null)) {
@@ -253,7 +241,6 @@
in.mPlayerAttr.getAllowedCapturePolicy() == ALLOW_CAPTURE_BY_ALL
? ALLOW_CAPTURE_BY_ALL : ALLOW_CAPTURE_BY_NONE)
.build();
- anonymCopy.mDeviceId = in.mDeviceId;
// anonymized data
anonymCopy.mPlayerType = PLAYER_TYPE_UNKNOWN;
anonymCopy.mClientUid = PLAYER_UPID_INVALID;
@@ -291,25 +278,6 @@
}
/**
- * Returns information about the {@link AudioDeviceInfo} used for this playback.
- * @return the audio playback device or null if the device is not available at the time of query
- */
- public @Nullable AudioDeviceInfo getAudioDevice() {
- if (mDeviceId == PLAYER_DEVICEID_INVALID) {
- return null;
- }
- // TODO(175802592): change this to AudioManager.getDeviceForPortId() when available
- AudioDeviceInfo[] devices =
- AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS);
- for (int i = 0; i < devices.length; i++) {
- if (devices[i].getId() == mDeviceId) {
- return devices[i];
- }
- }
- return null;
- }
-
- /**
* @hide
* Return the type of player linked to this configuration.
* <br>Note that player types not exposed in the system API will be represented as
@@ -391,29 +359,13 @@
* @hide
* Handle a player state change
* @param event
- * @param deviceId active device id or {@Code PLAYER_DEVICEID_INVALID}
- * <br>Note device id is valid for {@code PLAYER_UPDATE_DEVICE_ID} or
- * <br>{@code PLAYER_STATE_STARTED} events, as the device id will be reset to none when
- * <br>pausing or stopping playback. It will be set to active device when playback starts or
- * <br>it will be changed when PLAYER_UPDATE_DEVICE_ID is sent. The latter can happen if the
- * <br>device changes in the middle of playback.
* @return true if the state changed, false otherwise
*/
- public boolean handleStateEvent(int event, int deviceId) {
- boolean changed = false;
+ public boolean handleStateEvent(int event) {
+ final boolean changed;
synchronized (this) {
-
- // Do not update if it is only device id update
- if (event != PLAYER_UPDATE_DEVICE_ID) {
- changed = (mPlayerState != event);
- mPlayerState = event;
- }
-
- if (event == PLAYER_STATE_STARTED || event == PLAYER_UPDATE_DEVICE_ID) {
- changed = changed || (mDeviceId != deviceId);
- mDeviceId = deviceId;
- }
-
+ changed = (mPlayerState != event);
+ mPlayerState = event;
if (changed && (event == PLAYER_STATE_RELEASED) && (mIPlayerShell != null)) {
mIPlayerShell.release();
mIPlayerShell = null;
@@ -484,7 +436,7 @@
@Override
public int hashCode() {
- return Objects.hash(mPlayerIId, mDeviceId, mPlayerType, mClientUid, mClientPid);
+ return Objects.hash(mPlayerIId, mPlayerType, mClientUid, mClientPid);
}
@Override
@@ -495,7 +447,6 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mPlayerIId);
- dest.writeInt(mDeviceId);
dest.writeInt(mPlayerType);
dest.writeInt(mClientUid);
dest.writeInt(mClientPid);
@@ -510,7 +461,6 @@
private AudioPlaybackConfiguration(Parcel in) {
mPlayerIId = in.readInt();
- mDeviceId = in.readInt();
mPlayerType = in.readInt();
mClientUid = in.readInt();
mClientPid = in.readInt();
@@ -528,7 +478,6 @@
AudioPlaybackConfiguration that = (AudioPlaybackConfiguration) o;
return ((mPlayerIId == that.mPlayerIId)
- && (mDeviceId == that.mDeviceId)
&& (mPlayerType == that.mPlayerType)
&& (mClientUid == that.mClientUid)
&& (mClientPid == that.mClientPid));
@@ -537,7 +486,6 @@
@Override
public String toString() {
return "AudioPlaybackConfiguration piid:" + mPlayerIId
- + " deviceId:" + mDeviceId
+ " type:" + toLogFriendlyPlayerType(mPlayerType)
+ " u/pid:" + mClientUid + "/" + mClientPid
+ " state:" + toLogFriendlyPlayerState(mPlayerState)
@@ -623,7 +571,6 @@
case PLAYER_STATE_STARTED: return "started";
case PLAYER_STATE_PAUSED: return "paused";
case PLAYER_STATE_STOPPED: return "stopped";
- case PLAYER_UPDATE_DEVICE_ID: return "device";
default:
return "unknown player state - FIXME";
}
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 8987a71..164b194 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1730,7 +1730,7 @@
int[] types = new int[devices.size()];
String[] addresses = new String[devices.size()];
for (int i = 0; i < devices.size(); ++i) {
- types[i] = AudioDeviceInfo.convertDeviceTypeToInternalDevice(devices.get(i).getType());
+ types[i] = devices.get(i).getInternalType();
addresses[i] = devices.get(i).getAddress();
}
return setDevicesRoleForStrategy(strategy, role, types, addresses);
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index e9a18e9..e3b6fba 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1824,7 +1824,6 @@
@Override
protected void finalize() {
- tryToDisableNativeRoutingCallback();
baseRelease();
native_finalize();
}
@@ -2718,15 +2717,9 @@
}
private void startImpl() {
- synchronized (mRoutingChangeListeners) {
- if (!mEnableSelfRoutingMonitor) {
- testEnableNativeRoutingCallbacksLocked();
- mEnableSelfRoutingMonitor = true;
- }
- }
synchronized(mPlayStateLock) {
+ baseStart();
native_start();
- baseStart(native_getRoutedDeviceId());
if (mPlayState == PLAYSTATE_PAUSED_STOPPING) {
mPlayState = PLAYSTATE_STOPPING;
} else {
@@ -2764,7 +2757,6 @@
mPlayStateLock.notify();
}
}
- tryToDisableNativeRoutingCallback();
}
/**
@@ -3504,21 +3496,12 @@
return null;
}
- private void tryToDisableNativeRoutingCallback() {
- synchronized (mRoutingChangeListeners) {
- if (mEnableSelfRoutingMonitor) {
- mEnableSelfRoutingMonitor = false;
- testDisableNativeRoutingCallbacksLocked();
- }
- }
- }
-
/*
* Call BEFORE adding a routing callback handler.
*/
@GuardedBy("mRoutingChangeListeners")
private void testEnableNativeRoutingCallbacksLocked() {
- if (mRoutingChangeListeners.size() == 0 && !mEnableSelfRoutingMonitor) {
+ if (mRoutingChangeListeners.size() == 0) {
native_enableDeviceCallback();
}
}
@@ -3528,7 +3511,7 @@
*/
@GuardedBy("mRoutingChangeListeners")
private void testDisableNativeRoutingCallbacksLocked() {
- if (mRoutingChangeListeners.size() == 0 && !mEnableSelfRoutingMonitor) {
+ if (mRoutingChangeListeners.size() == 0) {
native_disableDeviceCallback();
}
}
@@ -3545,9 +3528,6 @@
private ArrayMap<AudioRouting.OnRoutingChangedListener,
NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
- @GuardedBy("mRoutingChangeListeners")
- private boolean mEnableSelfRoutingMonitor;
-
/**
* Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
* changes on this AudioTrack.
@@ -3647,7 +3627,6 @@
*/
private void broadcastRoutingChange() {
AudioManager.resetAudioPortGeneration();
- baseUpdateDeviceId(getRoutedDevice());
synchronized (mRoutingChangeListeners) {
for (NativeRoutingEventHandlerDelegate delegate : mRoutingChangeListeners.values()) {
delegate.notifyClient();
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index de885f49..8ea380a 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -83,6 +83,10 @@
* <p>
* Supported for writing: JPEG, PNG, WebP.
* <p>
+ * Note: JPEG and HEIF files may contain XMP data either inside the Exif data chunk or outside of
+ * it. This class will search both locations for XMP data, but if XMP data exist both inside and
+ * outside Exif, will favor the XMP data inside Exif over the one outside.
+ * <p>
* Note: It is recommended to use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
* <a href="{@docRoot}reference/androidx/exifinterface/media/ExifInterface.html">ExifInterface
* Library</a> since it is a superset of this class. In addition to the functionalities of this
@@ -3185,6 +3189,24 @@
readExifSegment(bytes, IFD_TYPE_PRIMARY);
}
+ String xmpOffsetStr = retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_XMP_OFFSET);
+ String xmpLengthStr = retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_XMP_LENGTH);
+ if (xmpOffsetStr != null && xmpLengthStr != null) {
+ int offset = Integer.parseInt(xmpOffsetStr);
+ int length = Integer.parseInt(xmpLengthStr);
+ in.seek(offset);
+ byte[] xmpBytes = new byte[length];
+ if (in.read(xmpBytes) != length) {
+ throw new IOException("Failed to read XMP from HEIF");
+ }
+ if (getAttribute(TAG_XMP) == null) {
+ mAttributes[IFD_TYPE_PRIMARY].put(TAG_XMP, new ExifAttribute(
+ IFD_FORMAT_BYTE, xmpBytes.length, offset, xmpBytes));
+ }
+ }
+
if (DEBUG) {
Log.d(TAG, "Heif meta: " + width + "x" + height + ", rotation " + rotation);
}
diff --git a/media/java/android/media/HwAudioSource.java b/media/java/android/media/HwAudioSource.java
index bbf632a..01a02f1 100644
--- a/media/java/android/media/HwAudioSource.java
+++ b/media/java/android/media/HwAudioSource.java
@@ -22,8 +22,6 @@
import com.android.internal.util.Preconditions;
-import java.util.ArrayList;
-
/**
* The HwAudioSource represents the audio playback directly from a source audio device.
* It currently supports {@link HwAudioSource#start()} and {@link HwAudioSource#stop()} only
@@ -132,32 +130,10 @@
*/
public void start() {
Preconditions.checkState(!isPlaying(), "HwAudioSource is currently playing");
+ baseStart();
mNativeHandle = AudioSystem.startAudioSource(
mAudioDeviceInfo.getPort().activeConfig(),
mAudioAttributes);
- // FIXME: b/174876389 clean up device id reporting
- baseStart(getDeviceId());
- }
-
- private int getDeviceId() {
- ArrayList<AudioPatch> patches = new ArrayList<AudioPatch>();
- if (AudioManager.listAudioPatches(patches) != AudioManager.SUCCESS) {
- return 0;
- }
-
- for (int i = 0; i < patches.size(); i++) {
- AudioPatch patch = patches.get(i);
- AudioPortConfig[] sources = patch.sources();
- AudioPortConfig[] sinks = patch.sinks();
- if ((sources != null) && (sources.length > 0)) {
- for (int c = 0; c < sources.length; c++) {
- if (sources[c].port().id() == mAudioDeviceInfo.getId()) {
- return sinks[c].port().id();
- }
- }
- }
- }
- return 0;
}
/**
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 77fde6a..bad0d19 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -28,6 +28,7 @@
import android.media.IAudioRoutesObserver;
import android.media.IAudioServerStateDispatcher;
import android.media.ICapturePresetDevicesRoleDispatcher;
+import android.media.ICommunicationDeviceDispatcher;
import android.media.IPlaybackConfigDispatcher;
import android.media.IRecordingConfigDispatcher;
import android.media.IRingtonePlayer;
@@ -62,7 +63,7 @@
oneway void playerAttributes(in int piid, in AudioAttributes attr);
- oneway void playerEvent(in int piid, in int event, in int deviceId);
+ oneway void playerEvent(in int piid, in int event);
oneway void releasePlayer(in int piid);
@@ -338,4 +339,13 @@
boolean isMusicActive(in boolean remotely);
int getDevicesForStream(in int streamType);
+
+ boolean setDeviceForCommunication(IBinder cb, int portId);
+
+ int getDeviceForCommunication();
+
+ void registerCommunicationDeviceDispatcher(ICommunicationDeviceDispatcher dispatcher);
+
+ oneway void unregisterCommunicationDeviceDispatcher(
+ ICommunicationDeviceDispatcher dispatcher);
}
diff --git a/media/java/android/media/ICommunicationDeviceDispatcher.aidl b/media/java/android/media/ICommunicationDeviceDispatcher.aidl
new file mode 100644
index 0000000..429f934
--- /dev/null
+++ b/media/java/android/media/ICommunicationDeviceDispatcher.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * AIDL for AudioService to signal audio communication device updates.
+ *
+ * {@hide}
+ */
+oneway interface ICommunicationDeviceDispatcher {
+
+ void dispatchCommunicationDeviceChanged(int portId);
+
+}
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index e7e83eb..9657b25e 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -1865,10 +1865,6 @@
&& aligned.mMaxMacroBlockRate >= otherAligned.mMaxMacroBlockRate);
}
- /* package private */ boolean isEqualDimension(@NonNull PerformancePoint other) {
- return mWidth == other.mWidth && mHeight == other.mHeight;
- }
-
private @NonNull Size getCommonBlockSize(@NonNull PerformancePoint other) {
return new Size(
Math.max(mBlockSize.getWidth(), other.mBlockSize.getWidth()) * 16,
@@ -2010,8 +2006,11 @@
* codecs are active, should use that highest pixel count, and add the frame rates of
* each individual codec.
* <p class=note>
- * Supported resolution could be further restricted for 32-bit processes due to
- * the limited virtual memory space.
+ * 32-bit processes will not support resolutions larger than 4096x4096 due to
+ * the limited address space, but performance points will be presented as is.
+ * In other words, even though a component publishes a performance point for
+ * a resolution higher than 4096x4096, it does not mean that the resolution is supported
+ * for 32-bit processes.
*/
@Nullable
public List<PerformancePoint> getSupportedPerformancePoints() {
@@ -2215,28 +2214,6 @@
(a.getMaxFrameRate() != b.getMaxFrameRate()) ?
(a.getMaxFrameRate() < b.getMaxFrameRate() ? -1 : 1) : 0));
- // remove redundant points
- for (int i = 1; i < ret.size(); ++i) {
- PerformancePoint a = ret.get(i);
- for (int j = 0; j < i; ++j) {
- PerformancePoint b = ret.get(j);
- if (b.isEqualDimension(a) && b.covers(a)) {
- ret.set(i, null);
- break;
- }
- }
- }
- int newSize = 0;
- for (int i = 0; i < ret.size(); ++i) {
- PerformancePoint a = ret.get(i);
- if (a == null) {
- continue;
- }
- ret.set(newSize, a);
- ++newSize;
- }
- ret.setSize(newSize);
-
return Collections.unmodifiableList(ret);
}
diff --git a/media/java/android/media/MediaFrameworkInitializer.java b/media/java/android/media/MediaFrameworkPlatformInitializer.java
similarity index 87%
rename from media/java/android/media/MediaFrameworkInitializer.java
rename to media/java/android/media/MediaFrameworkPlatformInitializer.java
index 577442e..e703669 100644
--- a/media/java/android/media/MediaFrameworkInitializer.java
+++ b/media/java/android/media/MediaFrameworkPlatformInitializer.java
@@ -28,11 +28,15 @@
/**
* Class for performing registration for all media services
*
- * TODO (b/160513103): Move this class when moving media service code to APEX
+ * TODO (b/160513103): This class is still needed on platform side until
+ * MEDIA_SESSION_SERVICE is moved onto com.android.media apex.
+ * Once that's done, we can move the code that registers the service onto the
+ * MediaFrameworkInitializer class on the apex.
+ *
* @hide
*/
-public class MediaFrameworkInitializer {
- private MediaFrameworkInitializer() {
+public class MediaFrameworkPlatformInitializer {
+ private MediaFrameworkPlatformInitializer() {
}
private static volatile MediaServiceManager sMediaServiceManager;
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 86d1d15..32a9168 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -1313,14 +1313,14 @@
public static final int METADATA_KEY_VIDEO_FRAME_COUNT = 32;
/**
- * If the media contains EXIF data, this key retrieves the offset value
+ * If the media contains EXIF data, this key retrieves the offset (in bytes)
* of the data.
*/
public static final int METADATA_KEY_EXIF_OFFSET = 33;
/**
- * If the media contains EXIF data, this key retrieves the length of the
- * data.
+ * If the media contains EXIF data, this key retrieves the length (in bytes)
+ * of the data.
*/
public static final int METADATA_KEY_EXIF_LENGTH = 34;
@@ -1371,5 +1371,21 @@
@SystemApi(client = MODULE_LIBRARIES)
public static final int METADATA_KEY_VIDEO_CODEC_MIME_TYPE = 40;
+ /**
+ * If the media contains XMP data, this key retrieves the offset (in bytes)
+ * of the data.
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int METADATA_KEY_XMP_OFFSET = 41;
+
+ /**
+ * If the media contains XMP data, this key retrieves the length (in bytes)
+ * of the data.
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int METADATA_KEY_XMP_LENGTH = 42;
+
// Add more here...
}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index ceac2c9..f8311cd 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1352,6 +1352,7 @@
}
private void startImpl() {
+ baseStart();
stayAwake(true);
_start();
}
@@ -1377,6 +1378,7 @@
public void stop() throws IllegalStateException {
stayAwake(false);
_stop();
+ baseStop();
}
private native void _stop() throws IllegalStateException;
@@ -1390,6 +1392,7 @@
public void pause() throws IllegalStateException {
stayAwake(false);
_pause();
+ basePause();
}
private native void _pause() throws IllegalStateException;
@@ -1494,60 +1497,13 @@
return null;
}
-
- /**
- * Sends device list change notification to all listeners.
- */
- private void broadcastRoutingChange() {
- AudioManager.resetAudioPortGeneration();
- synchronized (mRoutingChangeListeners) {
- // Prevent the case where an event is triggered by registering a routing change
- // listener via the media player.
- if (mEnableSelfRoutingMonitor) {
- baseUpdateDeviceId(getRoutedDevice());
- }
- for (NativeRoutingEventHandlerDelegate delegate
- : mRoutingChangeListeners.values()) {
- delegate.notifyClient();
- }
- }
- }
-
/*
- * Call BEFORE adding a routing callback handler.
+ * Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler.
*/
@GuardedBy("mRoutingChangeListeners")
- private void testEnableNativeRoutingCallbacksLocked() {
- if (mRoutingChangeListeners.size() == 0 && !mEnableSelfRoutingMonitor) {
- native_enableDeviceCallback(true);
- }
- }
-
- private void tryToEnableNativeRoutingCallback() {
- synchronized (mRoutingChangeListeners) {
- if (!mEnableSelfRoutingMonitor) {
- testEnableNativeRoutingCallbacksLocked();
- mEnableSelfRoutingMonitor = true;
- }
- }
- }
-
- private void tryToDisableNativeRoutingCallback() {
- synchronized (mRoutingChangeListeners) {
- if (mEnableSelfRoutingMonitor) {
- mEnableSelfRoutingMonitor = false;
- testDisableNativeRoutingCallbacksLocked();
- }
- }
- }
-
- /*
- * Call AFTER removing a routing callback handler.
- */
- @GuardedBy("mRoutingChangeListeners")
- private void testDisableNativeRoutingCallbacksLocked() {
- if (mRoutingChangeListeners.size() == 0 && !mEnableSelfRoutingMonitor) {
- native_enableDeviceCallback(false);
+ private void enableNativeRoutingCallbacksLocked(boolean enabled) {
+ if (mRoutingChangeListeners.size() == 0) {
+ native_enableDeviceCallback(enabled);
}
}
@@ -1560,9 +1516,6 @@
private ArrayMap<AudioRouting.OnRoutingChangedListener,
NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
- @GuardedBy("mRoutingChangeListeners")
- private boolean mEnableSelfRoutingMonitor;
-
/**
* Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
* changes on this MediaPlayer.
@@ -1576,7 +1529,7 @@
Handler handler) {
synchronized (mRoutingChangeListeners) {
if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
- testEnableNativeRoutingCallbacksLocked();
+ enableNativeRoutingCallbacksLocked(true);
mRoutingChangeListeners.put(
listener, new NativeRoutingEventHandlerDelegate(this, listener,
handler != null ? handler : mEventHandler));
@@ -1595,8 +1548,8 @@
synchronized (mRoutingChangeListeners) {
if (mRoutingChangeListeners.containsKey(listener)) {
mRoutingChangeListeners.remove(listener);
+ enableNativeRoutingCallbacksLocked(false);
}
- testDisableNativeRoutingCallbacksLocked();
}
}
@@ -3348,7 +3301,6 @@
@Override
protected void finalize() {
- tryToDisableNativeRoutingCallback();
baseRelease();
native_finalize();
}
@@ -3463,8 +3415,6 @@
case MEDIA_STOPPED:
{
- tryToDisableNativeRoutingCallback();
- baseStop();
TimeProvider timeProvider = mTimeProvider;
if (timeProvider != null) {
timeProvider.onStopped();
@@ -3473,16 +3423,8 @@
break;
case MEDIA_STARTED:
- {
- baseStart(native_getRoutedDeviceId());
- tryToEnableNativeRoutingCallback();
- }
- // fall through
case MEDIA_PAUSED:
{
- if (msg.what == MEDIA_PAUSED) {
- basePause();
- }
TimeProvider timeProvider = mTimeProvider;
if (timeProvider != null) {
timeProvider.onPaused(msg.what == MEDIA_PAUSED);
@@ -3648,8 +3590,14 @@
break;
case MEDIA_AUDIO_ROUTING_CHANGED:
- broadcastRoutingChange();
- return;
+ AudioManager.resetAudioPortGeneration();
+ synchronized (mRoutingChangeListeners) {
+ for (NativeRoutingEventHandlerDelegate delegate
+ : mRoutingChangeListeners.values()) {
+ delegate.notifyClient();
+ }
+ }
+ return;
case MEDIA_TIME_DISCONTINUITY:
final OnMediaTimeDiscontinuityListener mediaTimeListener;
@@ -3855,7 +3803,6 @@
@Override
public void onCompletion(MediaPlayer mp) {
baseStop();
- tryToDisableNativeRoutingCallback();
}
};
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 36f7bed..d0304f2 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -23,6 +23,9 @@
import android.annotation.Nullable;
import android.annotation.SystemService;
import android.app.ActivityThread;
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHearingAid;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -99,6 +102,7 @@
RouteInfo mDefaultAudioVideo;
RouteInfo mBluetoothA2dpRoute;
+ volatile boolean mHasActiveBluetoothDevices;
RouteInfo mSelectedRoute;
@@ -172,14 +176,20 @@
new IntentFilter(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED));
appContext.registerReceiver(new VolumeChangeReceiver(),
new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION));
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED);
+ intentFilter.addAction(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED);
+ appContext.registerReceiver(new BluetoothStateChangedReceiver(), intentFilter);
mDisplayService.registerDisplayListener(this, mHandler);
AudioRoutesInfo newAudioRoutes = null;
try {
newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver);
+ mHasActiveBluetoothDevices = mAudioService.isBluetoothA2dpOn();
} catch (RemoteException e) {
}
+
if (newAudioRoutes != null) {
// This will select the active BT route if there is one and the current
// selected route is the default system route, or if there is no selected
@@ -253,7 +263,8 @@
}
if (audioRoutesChanged) {
- Log.v(TAG, "Audio routes updated: " + newRoutes + ", a2dp=" + isBluetoothA2dpOn());
+ Log.v(TAG, "Audio routes updated: " + newRoutes + ", hasActiveBTDevices="
+ + mHasActiveBluetoothDevices);
if (mSelectedRoute == null || mSelectedRoute == mDefaultAudioVideo
|| mSelectedRoute == mBluetoothA2dpRoute) {
if (forceUseDefaultRoute || mBluetoothA2dpRoute == null) {
@@ -277,15 +288,6 @@
return mStreamVolume.get(streamType);
}
- boolean isBluetoothA2dpOn() {
- try {
- return mBluetoothA2dpRoute != null && mAudioService.isBluetoothA2dpOn();
- } catch (RemoteException e) {
- Log.e(TAG, "Error querying Bluetooth A2DP state", e);
- return false;
- }
- }
-
void updateDiscoveryRequest() {
// What are we looking for today?
int routeTypes = 0;
@@ -394,7 +396,7 @@
}
void updateSelectedRouteForId(String routeId) {
- RouteInfo selectedRoute = isBluetoothA2dpOn()
+ RouteInfo selectedRoute = sStatic.mHasActiveBluetoothDevices
? mBluetoothA2dpRoute : mDefaultAudioVideo;
final int count = mRoutes.size();
for (int i = 0; i < count; i++) {
@@ -1043,7 +1045,7 @@
Log.v(TAG, "Selecting route: " + route);
assert(route != null);
final RouteInfo oldRoute = sStatic.mSelectedRoute;
- final RouteInfo currentSystemRoute = sStatic.isBluetoothA2dpOn()
+ final RouteInfo currentSystemRoute = sStatic.mHasActiveBluetoothDevices
? sStatic.mBluetoothA2dpRoute : sStatic.mDefaultAudioVideo;
boolean wasDefaultOrBluetoothRoute = (oldRoute == sStatic.mDefaultAudioVideo
|| oldRoute == sStatic.mBluetoothA2dpRoute);
@@ -1106,7 +1108,8 @@
static void selectDefaultRouteStatic() {
// TODO: Be smarter about the route types here; this selects for all valid.
- if (sStatic.mSelectedRoute != sStatic.mBluetoothA2dpRoute && sStatic.isBluetoothA2dpOn()) {
+ if (sStatic.mSelectedRoute != sStatic.mBluetoothA2dpRoute
+ && sStatic.mHasActiveBluetoothDevices) {
selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mBluetoothA2dpRoute, false);
} else {
selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mDefaultAudioVideo, false);
@@ -1443,13 +1446,8 @@
if (selectedRoute == sStatic.mBluetoothA2dpRoute ||
selectedRoute == sStatic.mDefaultAudioVideo) {
dispatchRouteVolumeChanged(selectedRoute);
- } else if (sStatic.mBluetoothA2dpRoute != null) {
- try {
- dispatchRouteVolumeChanged(sStatic.mAudioService.isBluetoothA2dpOn() ?
- sStatic.mBluetoothA2dpRoute : sStatic.mDefaultAudioVideo);
- } catch (RemoteException e) {
- Log.e(TAG, "Error checking Bluetooth A2DP state to report volume change", e);
- }
+ } else if (sStatic.mHasActiveBluetoothDevices) {
+ dispatchRouteVolumeChanged(sStatic.mBluetoothA2dpRoute);
} else {
dispatchRouteVolumeChanged(sStatic.mDefaultAudioVideo);
}
@@ -3172,4 +3170,17 @@
}
}
}
+
+ static class BluetoothStateChangedReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ switch (intent.getAction()) {
+ case BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED:
+ case BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED:
+ sStatic.mHasActiveBluetoothDevices =
+ intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE) != null;
+ break;
+ }
+ }
+ }
}
diff --git a/media/java/android/media/MediaServiceManager.java b/media/java/android/media/MediaServiceManager.java
index 21e2d84..96bff4f 100644
--- a/media/java/android/media/MediaServiceManager.java
+++ b/media/java/android/media/MediaServiceManager.java
@@ -17,6 +17,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.SystemApi.Client;
import android.os.IBinder;
import android.os.ServiceManager;
@@ -27,7 +29,11 @@
* <p> Only the media mainline module will be able to access an instance of this class.
* @hide
*/
+@SystemApi(client = Client.MODULE_LIBRARIES)
public class MediaServiceManager {
+ private static final String MEDIA_SESSION_SERVICE = "media_session";
+ private static final String MEDIA_TRANSCODING_SERVICE = "media.transcoding";
+
/**
* @hide
*/
@@ -59,10 +65,18 @@
}
/**
- * Returns {@link ServiceRegisterer} for the "media_session" service.
+ * Returns {@link ServiceRegisterer} for MEDIA_SESSION_SERVICE.
*/
@NonNull
public ServiceRegisterer getMediaSessionServiceRegisterer() {
- return new ServiceRegisterer("media_session");
+ return new ServiceRegisterer(MEDIA_SESSION_SERVICE);
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for MEDIA_TRANSCODING_SERVICE.
+ */
+ @NonNull
+ public ServiceRegisterer getMediaTranscodingServiceRegisterer() {
+ return new ServiceRegisterer(MEDIA_TRANSCODING_SERVICE);
}
}
diff --git a/media/java/android/media/OWNERS b/media/java/android/media/OWNERS
index cbc9ab7..cf06fad 100644
--- a/media/java/android/media/OWNERS
+++ b/media/java/android/media/OWNERS
@@ -6,3 +6,4 @@
olly@google.com
andrewlewis@google.com
sungsoo@google.com
+jmtrivi@google.com
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index 58ae279..da69c6c 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -90,8 +90,6 @@
private float mPanMultiplierR = 1.0f;
@GuardedBy("mLock")
private float mVolMultiplier = 1.0f;
- @GuardedBy("mLock")
- private int mDeviceId;
/**
* Constructor. Must be given audio attributes, as they are required for AppOps.
@@ -154,35 +152,14 @@
}
}
- void baseUpdateDeviceId(@Nullable AudioDeviceInfo deviceInfo) {
- int deviceId = 0;
- if (deviceInfo != null) {
- deviceId = deviceInfo.getId();
- }
- int piid;
- synchronized (mLock) {
- piid = mPlayerIId;
- mDeviceId = deviceId;
- }
- try {
- getService().playerEvent(piid,
- AudioPlaybackConfiguration.PLAYER_UPDATE_DEVICE_ID, deviceId);
- } catch (RemoteException e) {
- Log.e(TAG, "Error talking to audio service, "
- + deviceId
- + " device id will not be tracked for piid=" + piid, e);
- }
- }
-
- private void updateState(int state, int deviceId) {
+ private void updateState(int state) {
final int piid;
synchronized (mLock) {
mState = state;
piid = mPlayerIId;
- mDeviceId = deviceId;
}
try {
- getService().playerEvent(piid, state, deviceId);
+ getService().playerEvent(piid, state);
} catch (RemoteException e) {
Log.e(TAG, "Error talking to audio service, "
+ AudioPlaybackConfiguration.toLogFriendlyPlayerState(state)
@@ -190,11 +167,9 @@
}
}
- void baseStart(int deviceId) {
- if (DEBUG) {
- Log.v(TAG, "baseStart() piid=" + mPlayerIId + " deviceId=" + deviceId);
- }
- updateState(AudioPlaybackConfiguration.PLAYER_STATE_STARTED, deviceId);
+ void baseStart() {
+ if (DEBUG) { Log.v(TAG, "baseStart() piid=" + mPlayerIId); }
+ updateState(AudioPlaybackConfiguration.PLAYER_STATE_STARTED);
synchronized (mLock) {
if (isRestricted_sync()) {
playerSetVolume(true/*muting*/,0, 0);
@@ -216,12 +191,12 @@
void basePause() {
if (DEBUG) { Log.v(TAG, "basePause() piid=" + mPlayerIId); }
- updateState(AudioPlaybackConfiguration.PLAYER_STATE_PAUSED, 0);
+ updateState(AudioPlaybackConfiguration.PLAYER_STATE_PAUSED);
}
void baseStop() {
if (DEBUG) { Log.v(TAG, "baseStop() piid=" + mPlayerIId); }
- updateState(AudioPlaybackConfiguration.PLAYER_STATE_STOPPED, 0);
+ updateState(AudioPlaybackConfiguration.PLAYER_STATE_STOPPED);
}
void baseSetPan(float pan) {
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index 797caf3..3f685a4 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -303,8 +303,7 @@
*/
public final int play(int soundID, float leftVolume, float rightVolume,
int priority, int loop, float rate) {
- // FIXME: b/174876164 implement device id for soundpool
- baseStart(0);
+ baseStart();
return _play(soundID, leftVolume, rightVolume, priority, loop, rate);
}
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 6af39f8..00ee914 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -28,7 +28,7 @@
import android.content.pm.ParceledListSlice;
import android.media.AudioManager;
import android.media.IRemoteVolumeControllerCallback;
-import android.media.MediaFrameworkInitializer;
+import android.media.MediaFrameworkPlatformInitializer;
import android.media.MediaSession2;
import android.media.Session2Token;
import android.os.Bundle;
@@ -122,7 +122,7 @@
// Consider rewriting like DisplayManagerGlobal
// Decide if we need context
mContext = context;
- mService = ISessionManager.Stub.asInterface(MediaFrameworkInitializer
+ mService = ISessionManager.Stub.asInterface(MediaFrameworkPlatformInitializer
.getMediaServiceManager()
.getMediaSessionServiceRegisterer()
.get());
@@ -180,7 +180,7 @@
* be provided in priority order with the most important controller at index
* 0.
* <p>
- * This requires the android.Manifest.permission.MEDIA_CONTENT_CONTROL
+ * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL}
* permission be held by the calling app. You may also retrieve this list if
* your app is an enabled notification listener using the
* {@link NotificationListenerService} APIs, in which case you must pass the
@@ -196,14 +196,18 @@
}
/**
- * Get active sessions for a specific user. To retrieve actions for a user
- * other than your own you must hold the
- * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission
- * in addition to any other requirements. If you are an enabled notification
- * listener you may only get sessions for the users you are enabled for.
+ * Get active sessions for the given user.
+ * <p>
+ * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be
+ * held by the calling app. You may also retrieve this list if your app is an enabled
+ * notification listener using the {@link NotificationListenerService} APIs, in which case you
+ * must pass the {@link ComponentName} of your enabled listener.
+ * <p>
+ * The calling application needs to hold the
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission in order to
+ * retrieve sessions for user ids that do not belong to current process.
*
- * @param notificationListener The enabled notification listener component.
- * May be null.
+ * @param notificationListener The enabled notification listener component. May be null.
* @param userId The user id to fetch sessions for.
* @return A list of controllers for ongoing sessions.
* @hide
@@ -248,8 +252,9 @@
* Gets a list of {@link Session2Token} with type {@link Session2Token#TYPE_SESSION} for the
* given user.
* <p>
- * If you want to get tokens for another user, you must hold the
- * android.Manifest.permission#INTERACT_ACROSS_USERS_FULL permission.
+ * The calling application needs to hold the
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission in order to
+ * retrieve session tokens for user ids that do not belong to current process.
*
* @param userId The user id to fetch sessions for.
* @return A list of {@link Session2Token}
@@ -267,11 +272,12 @@
}
/**
- * Add a listener to be notified when the list of active sessions changes. This requires the
- * {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be held by the calling
- * app. You may also retrieve this list if your app is an enabled notification listener using
- * the {@link NotificationListenerService} APIs, in which case you must pass the
- * {@link ComponentName} of your enabled listener.
+ * Add a listener to be notified when the list of active sessions changes.
+ * <p>
+ * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be
+ * held by the calling app. You may also retrieve this list if your app is an enabled
+ * notificationlistener using the {@link NotificationListenerService} APIs, in which case you
+ * must pass the {@link ComponentName} of your enabled listener.
*
* @param sessionListener The listener to add.
* @param notificationListener The enabled notification listener component. May be null.
@@ -283,12 +289,13 @@
}
/**
- * Add a listener to be notified when the list of active sessions changes. This requires the
- * {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be held by the calling
- * app. You may also retrieve this list if your app is an enabled notification listener using
- * the {@link NotificationListenerService} APIs, in which case you must pass the
- * {@link ComponentName} of your enabled listener. Updates will be posted to the handler
- * specified or to the caller's thread if the handler is null.
+ * Add a listener to be notified when the list of active sessions changes.
+ * <p>
+ * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be
+ * held by the calling app. You may also retrieve this list if your app is an enabled
+ * notification listener using the {@link NotificationListenerService} APIs, in which case you
+ * must pass the {@link ComponentName} of your enabled listener. Updates will be posted to the
+ * handler specified or to the caller's thread if the handler is null.
*
* @param sessionListener The listener to add.
* @param notificationListener The enabled notification listener component. May be null.
@@ -302,15 +309,17 @@
}
/**
- * Add a listener to be notified when the list of active sessions changes for the given user.
- * The calling app must have the {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}
- * permission if it wants to call this method for a user that is not running the app.
+ * Add a listener to be notified when the list of active sessions changes.
* <p>
* This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be
* held by the calling app. You may also retrieve this list if your app is an enabled
* notification listener using the {@link NotificationListenerService} APIs, in which case you
* must pass the {@link ComponentName} of your enabled listener. Updates will be posted to the
* handler specified or to the caller's thread if the handler is null.
+ * <p>
+ * The calling application needs to hold the
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission in order to
+ * add listeners for user ids that do not belong to current process.
*
* @param sessionListener The listener to add.
* @param notificationListener The enabled notification listener component. May be null.
@@ -407,6 +416,10 @@
* Library</a> for consistent behavior across all devices.
* <p>
* Adds a listener to be notified when the {@link #getSession2Tokens()} changes.
+ * <p>
+ * The calling application needs to hold the
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission in order to
+ * add listeners for user ids that do not belong to current process.
*
* @param userId The userId to listen for changes on
* @param listener The listener to add
@@ -705,8 +718,9 @@
/**
* Checks whether the remote user is a trusted app.
* <p>
- * An app is trusted if the app holds the android.Manifest.permission.MEDIA_CONTENT_CONTROL
- * permission or has an enabled notification listener.
+ * An app is trusted if the app holds the
+ * {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission or has an enabled
+ * notification listener.
*
* @param userInfo The remote user info from either
* {@link MediaSession#getCurrentControllerInfo()} or
diff --git a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
index 8871167..c4b622d 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
@@ -47,6 +47,7 @@
private static int sInstantId = 0;
private int mSegmentId = 0;
private int mOverflow;
+ private Boolean mIsStopped = null;
private native int nativeAttachFilter(Filter filter);
private native int nativeDetachFilter(Filter filter);
@@ -135,7 +136,13 @@
.write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId,
FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__RECORD,
FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STARTED, mSegmentId, 0);
- return nativeStartDvr();
+ synchronized (mIsStopped) {
+ int result = nativeStartDvr();
+ if (result == Tuner.RESULT_SUCCESS) {
+ mIsStopped = false;
+ }
+ return result;
+ }
}
/**
@@ -152,7 +159,13 @@
.write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId,
FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__RECORD,
FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STOPPED, mSegmentId, mOverflow);
- return nativeStopDvr();
+ synchronized (mIsStopped) {
+ int result = nativeStopDvr();
+ if (result == Tuner.RESULT_SUCCESS) {
+ mIsStopped = true;
+ }
+ return result;
+ }
}
/**
@@ -164,7 +177,13 @@
*/
@Result
public int flush() {
- return nativeFlushDvr();
+ synchronized (mIsStopped) {
+ if (mIsStopped) {
+ return nativeFlushDvr();
+ }
+ Log.w(TAG, "Cannot flush non-stopped Record DVR.");
+ return Tuner.RESULT_INVALID_STATE;
+ }
}
/**
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 440d5bc..6fa94f1 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -337,8 +337,8 @@
/////////////// MediaEvent ///////////////////////
-MediaEvent::MediaEvent(sp<Filter> filter, hidl_handle avHandle,
- uint64_t dataId, uint64_t dataSize, jobject obj) : mFilter(filter),
+MediaEvent::MediaEvent(sp<FilterClient> filterClient, hidl_handle avHandle,
+ uint64_t dataId, uint64_t dataSize, jobject obj) : mFilterClient(filterClient),
mDataId(dataId), mDataSize(dataSize), mBuffer(nullptr),
mDataIdRefCnt(0), mAvHandleRefCnt(0), mIonHandle(nullptr) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -359,12 +359,13 @@
if (pC2Buffer != NULL) {
pC2Buffer->unregisterOnDestroyNotify(&DestroyCallback, this);
}
+ mFilterClient = NULL;
}
void MediaEvent::finalize() {
- if (mAvHandleRefCnt == 0) {
- mFilter->mFilterSp->releaseAvHandle(
- hidl_handle(mAvHandle), mDataIdRefCnt == 0 ? mDataId : 0);
+ if (mAvHandleRefCnt == 0 && mFilterClient != NULL) {
+ mFilterClient->releaseAvHandle(
+ mAvHandle, mDataIdRefCnt == 0 ? mDataId : 0);
native_handle_close(mAvHandle);
}
}
@@ -382,21 +383,25 @@
int numInts = 0;
int memIndex;
int dataSize;
+ SharedHandleInfo info = mFilterClient->getAvSharedHandleInfo();
+ native_handle_t* avSharedHandle = info.sharedHandle;
+ uint64_t avSharedMemSize = info.size;
+
if (mAvHandle->numFds == 0) {
- if (mFilter->mAvSharedHandle == NULL) {
+ if (avSharedHandle == NULL) {
ALOGE("Shared AV memory handle is not initialized.");
return NULL;
}
- if (mFilter->mAvSharedHandle->numFds == 0) {
+ if (avSharedHandle->numFds == 0) {
ALOGE("Shared AV memory handle is empty.");
return NULL;
}
- fd = mFilter->mAvSharedHandle->data[0];
- dataSize = mFilter->mAvSharedMemSize;
- numInts = mFilter->mAvSharedHandle->numInts;
+ fd = avSharedHandle->data[0];
+ dataSize = avSharedMemSize;
+ numInts = avSharedHandle->numInts;
if (numInts > 0) {
// If the first int in the shared native handle has value, use it as the index
- memIndex = mFilter->mAvSharedHandle->data[mFilter->mAvSharedHandle->numFds];
+ memIndex = avSharedHandle->data[avSharedHandle->numFds];
}
} else {
fd = mAvHandle->data[0];
@@ -407,11 +412,11 @@
// event has value, use it as the index
memIndex = mAvHandle->data[mAvHandle->numFds];
} else {
- if (mFilter->mAvSharedHandle != NULL) {
- numInts = mFilter->mAvSharedHandle->numInts;
+ if (avSharedHandle != NULL) {
+ numInts = avSharedHandle->numInts;
if (numInts > 0) {
// If the first int in the shared native handle has value, use it as the index
- memIndex = mFilter->mAvSharedHandle->data[mFilter->mAvSharedHandle->numFds];
+ memIndex = avSharedHandle->data[avSharedHandle->numFds];
}
}
}
@@ -462,9 +467,9 @@
return mDataId;
}
-/////////////// FilterCallback ///////////////////////
+/////////////// FilterClientCallbackImpl ///////////////////////
-jobjectArray FilterCallback::getSectionEvent(
+jobjectArray FilterClientCallbackImpl::getSectionEvent(
jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/SectionEvent");
@@ -486,7 +491,7 @@
return arr;
}
-jobjectArray FilterCallback::getMediaEvent(
+jobjectArray FilterClientCallbackImpl::getMediaEvent(
jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/MediaEvent");
@@ -537,7 +542,7 @@
if (mediaEvent.avMemory.getNativeHandle() != NULL || mediaEvent.avDataId != 0) {
sp<MediaEvent> mediaEventSp =
- new MediaEvent(mFilter, mediaEvent.avMemory,
+ new MediaEvent(mFilterClient, mediaEvent.avMemory,
mediaEvent.avDataId, dataLength + offset, obj);
mediaEventSp->mAvHandleRefCnt++;
env->SetLongField(obj, eventContext, (jlong) mediaEventSp.get());
@@ -549,7 +554,7 @@
return arr;
}
-jobjectArray FilterCallback::getPesEvent(
+jobjectArray FilterClientCallbackImpl::getPesEvent(
jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/PesEvent");
@@ -570,7 +575,7 @@
return arr;
}
-jobjectArray FilterCallback::getTsRecordEvent(
+jobjectArray FilterClientCallbackImpl::getTsRecordEvent(
jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events,
const std::vector<DemuxFilterEventExt::Event>& eventsExt) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -623,7 +628,7 @@
return arr;
}
-jobjectArray FilterCallback::getMmtpRecordEvent(
+jobjectArray FilterClientCallbackImpl::getMmtpRecordEvent(
jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events,
const std::vector<DemuxFilterEventExt::Event>& eventsExt) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -665,7 +670,7 @@
return arr;
}
-jobjectArray FilterCallback::getDownloadEvent(
+jobjectArray FilterClientCallbackImpl::getDownloadEvent(
jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/DownloadEvent");
@@ -689,7 +694,7 @@
return arr;
}
-jobjectArray FilterCallback::getIpPayloadEvent(
+jobjectArray FilterClientCallbackImpl::getIpPayloadEvent(
jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/IpPayloadEvent");
@@ -705,7 +710,7 @@
return arr;
}
-jobjectArray FilterCallback::getTemiEvent(
+jobjectArray FilterClientCallbackImpl::getTemiEvent(
jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/TemiEvent");
@@ -728,7 +733,7 @@
return arr;
}
-jobjectArray FilterCallback::getScramblingStatusEvent(
+jobjectArray FilterClientCallbackImpl::getScramblingStatusEvent(
jobjectArray& arr, const std::vector<DemuxFilterEventExt::Event>& eventsExt) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/ScramblingStatusEvent");
@@ -740,7 +745,7 @@
return arr;
}
-jobjectArray FilterCallback::getIpCidChangeEvent(
+jobjectArray FilterClientCallbackImpl::getIpCidChangeEvent(
jobjectArray& arr, const std::vector<DemuxFilterEventExt::Event>& eventsExt) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/IpCidChangeEvent");
@@ -752,7 +757,7 @@
return arr;
}
-jobjectArray FilterCallback::getRestartEvent(
+jobjectArray FilterClientCallbackImpl::getRestartEvent(
jobjectArray& arr, const std::vector<DemuxFilterEventExt::Event>& eventsExt) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/RestartEvent");
@@ -764,9 +769,9 @@
return arr;
}
-Return<void> FilterCallback::onFilterEvent_1_1(const DemuxFilterEvent& filterEvent,
+void FilterClientCallbackImpl::onFilterEvent_1_1(const DemuxFilterEvent& filterEvent,
const DemuxFilterEventExt& filterEventExt) {
- ALOGD("FilterCallback::onFilterEvent_1_1");
+ ALOGD("FilterClientCallbackImpl::onFilterEvent_1_1");
JNIEnv *env = AndroidRuntime::getJNIEnv();
jobjectArray array;
@@ -848,14 +853,13 @@
}
}
env->CallVoidMethod(
- mFilter->mFilterObj,
+ mFilterObj,
gFields.onFilterEventID,
array);
- return Void();
}
-Return<void> FilterCallback::onFilterEvent(const DemuxFilterEvent& filterEvent) {
- ALOGD("FilterCallback::onFilterEvent");
+void FilterClientCallbackImpl::onFilterEvent(const DemuxFilterEvent& filterEvent) {
+ ALOGD("FilterClientCallbackImpl::onFilterEvent");
std::vector<DemuxFilterEventExt::Event> emptyEventsExt;
DemuxFilterEventExt emptyFilterEventExt {
.events = emptyEventsExt,
@@ -863,49 +867,20 @@
return onFilterEvent_1_1(filterEvent, emptyFilterEventExt);
}
-Return<void> FilterCallback::onFilterStatus(const DemuxFilterStatus status) {
- ALOGD("FilterCallback::onFilterStatus");
+void FilterClientCallbackImpl::onFilterStatus(const DemuxFilterStatus status) {
+ ALOGD("FilterClientCallbackImpl::onFilterStatus");
JNIEnv *env = AndroidRuntime::getJNIEnv();
env->CallVoidMethod(
- mFilter->mFilterObj,
+ mFilterObj,
gFields.onFilterStatusID,
(jint)status);
- return Void();
}
-void FilterCallback::setFilter(const sp<Filter> filter) {
- ALOGD("FilterCallback::setFilter");
- // JNI Object
- mFilter = filter;
-}
-
-FilterCallback::~FilterCallback() {}
-
-/////////////// Filter ///////////////////////
-
-Filter::Filter(sp<IFilter> sp, jobject obj) : mFilterSp(sp) {
- JNIEnv *env = AndroidRuntime::getJNIEnv();
- mFilterObj = env->NewWeakGlobalRef(obj);
-}
-
-Filter::~Filter() {
- JNIEnv *env = AndroidRuntime::getJNIEnv();
-
- env->DeleteWeakGlobalRef(mFilterObj);
- mFilterObj = NULL;
- EventFlag::deleteEventFlag(&mFilterMQEventFlag);
-}
-
-int Filter::close() {
- Result r = mFilterSp->close();
- if (r == Result::SUCCESS) {
- EventFlag::deleteEventFlag(&mFilterMQEventFlag);
- }
- return (int)r;
-}
-
-sp<IFilter> Filter::getIFilter() {
- return mFilterSp;
+void FilterClientCallbackImpl::setFilter(jweak filterObj, sp<FilterClient> filterClient) {
+ ALOGD("FilterClientCallbackImpl::setFilter");
+ // Java Object
+ mFilterObj = filterObj;
+ mFilterClient = filterClient;
}
/////////////// TimeFilter ///////////////////////
@@ -927,22 +902,23 @@
return mTimeFilterSp;
}
-/////////////// FrontendCallback ///////////////////////
+/////////////// FrontendClientCallbackImpl ///////////////////////
-FrontendCallback::FrontendCallback(jweak tunerObj, FrontendId id) : mObject(tunerObj), mId(id) {}
+FrontendClientCallbackImpl::FrontendClientCallbackImpl(
+ jweak tunerObj, FrontendId id) : mObject(tunerObj), mId(id) {}
-Return<void> FrontendCallback::onEvent(FrontendEventType frontendEventType) {
- ALOGD("FrontendCallback::onEvent, type=%d", frontendEventType);
+void FrontendClientCallbackImpl::onEvent(FrontendEventType frontendEventType) {
+ ALOGD("FrontendClientCallbackImpl::onEvent, type=%d", frontendEventType);
JNIEnv *env = AndroidRuntime::getJNIEnv();
env->CallVoidMethod(
mObject,
gFields.onFrontendEventID,
(jint)frontendEventType);
- return Void();
}
-Return<void> FrontendCallback::onScanMessage(FrontendScanMessageType type, const FrontendScanMessage& message) {
- ALOGD("FrontendCallback::onScanMessage, type=%d", type);
+void FrontendClientCallbackImpl::onScanMessage(
+ FrontendScanMessageType type, const FrontendScanMessage& message) {
+ ALOGD("FrontendClientCallbackImpl::onScanMessage, type=%d", type);
JNIEnv *env = AndroidRuntime::getJNIEnv();
jclass clazz = env->FindClass("android/media/tv/tuner/Tuner");
switch(type) {
@@ -1050,13 +1026,15 @@
mObject,
env->GetMethodID(clazz, "onDvbsStandard", "(I)V"),
standard);
- } else if (std.getDiscriminator() == FrontendScanMessage::Standard::hidl_discriminator::tStd) {
+ } else if (std.getDiscriminator() ==
+ FrontendScanMessage::Standard::hidl_discriminator::tStd) {
standard = (jint) std.tStd();
env->CallVoidMethod(
mObject,
env->GetMethodID(clazz, "onDvbtStandard", "(I)V"),
standard);
- } else if (std.getDiscriminator() == FrontendScanMessage::Standard::hidl_discriminator::sifStd) {
+ } else if (std.getDiscriminator() ==
+ FrontendScanMessage::Standard::hidl_discriminator::sifStd) {
standard = (jint) std.sifStd();
env->CallVoidMethod(
mObject,
@@ -1081,17 +1059,17 @@
}
env->CallVoidMethod(
mObject,
- env->GetMethodID(clazz, "onAtsc3PlpInfos", "([Landroid/media/tv/tuner/frontend/Atsc3PlpInfo;)V"),
+ env->GetMethodID(clazz, "onAtsc3PlpInfos",
+ "([Landroid/media/tv/tuner/frontend/Atsc3PlpInfo;)V"),
array);
break;
}
}
- return Void();
}
-Return<void> FrontendCallback::onScanMessageExt1_1(FrontendScanMessageTypeExt1_1 type,
+void FrontendClientCallbackImpl::onScanMessageExt1_1(FrontendScanMessageTypeExt1_1 type,
const FrontendScanMessageExt1_1& message) {
- ALOGD("FrontendCallback::onScanMessageExt1_1, type=%d", type);
+ ALOGD("FrontendClientCallbackImpl::onScanMessageExt1_1, type=%d", type);
JNIEnv *env = AndroidRuntime::getJNIEnv();
jclass clazz = env->FindClass("android/media/tv/tuner/Tuner");
switch(type) {
@@ -1165,7 +1143,6 @@
default:
break;
}
- return Void();
}
/////////////// Tuner ///////////////////////
@@ -1202,7 +1179,11 @@
env->DeleteWeakGlobalRef(mObject);
env->DeleteGlobalRef(mClass);
mTuner = NULL;
+ mFe = NULL;
+ mDemux = NULL;
mTunerClient = NULL;
+ mFeClient = NULL;
+ mDemuxClient = NULL;
mClass = NULL;
mObject = NULL;
}
@@ -1252,9 +1233,11 @@
return obj;
}
-jobject JTuner::openFrontendById(int id) {
+jobject JTuner::openFrontendByHandle(int feHandle) {
sp<IFrontend> fe;
Result res;
+ uint32_t id = getResourceIdFromHandle(feHandle);
+
mTuner->openFrontendById(id, [&](Result r, const sp<IFrontend>& frontend) {
fe = frontend;
res = r;
@@ -1269,11 +1252,25 @@
if (mDemux != NULL) {
mDemux->setFrontendDataSource(mFeId);
}
- sp<FrontendCallback> feCb = new FrontendCallback(mObject, id);
- fe->setCallback(feCb);
jint jId = (jint) id;
+ // TODO: Handle reopening frontend with different handle
+ sp<FrontendClient> feClient = mTunerClient->openFrontend(feHandle);
+ if (feClient == NULL) {
+ ALOGE("Failed to open frontend");
+ return NULL;
+ }
+ mFeClient = feClient;
+
+ mFeId = mFeClient->getId();
+ jId = (jint) id;
+ if (mDemuxClient != NULL) {
+ mDemuxClient->setFrontendDataSource(mFeClient);
+ }
+ sp<FrontendClientCallbackImpl> feClientCb = new FrontendClientCallbackImpl(mObject, id);
+ mFeClient->setCallback(feClientCb);
+
JNIEnv *env = AndroidRuntime::getJNIEnv();
// TODO: add more fields to frontend
return env->NewObject(
@@ -1589,30 +1586,19 @@
}
int JTuner::tune(const FrontendSettings& settings, const FrontendSettingsExt1_1& settingsExt1_1) {
- if (mFe == NULL) {
+ if (mFeClient == nullptr) {
ALOGE("frontend is not initialized");
return (int)Result::INVALID_STATE;
}
- Result result;
- sp<::android::hardware::tv::tuner::V1_1::IFrontend> fe_1_1 =
- ::android::hardware::tv::tuner::V1_1::IFrontend::castFrom(mFe);
- if (fe_1_1 == NULL) {
- ALOGD("1.1 frontend is not found. Using 1.0 instead.");
- result = mFe->tune(settings);
- return (int)result;
- }
-
- result = fe_1_1->tune_1_1(settings, settingsExt1_1);
- return (int)result;
+ return (int) mFeClient->tune(settings,settingsExt1_1);
}
int JTuner::stopTune() {
- if (mFe == NULL) {
+ if (mFeClient == nullptr) {
ALOGE("frontend is not initialized");
return (int)Result::INVALID_STATE;
}
- Result result = mFe->stopTune();
- return (int)result;
+ return (int) mFeClient->stopTune();
}
int JTuner::scan(const FrontendSettings& settings, FrontendScanType scanType,
@@ -1662,28 +1648,47 @@
}
Result JTuner::openDemux() {
- if (mTuner == nullptr) {
+ if (mTuner == nullptr || mTunerClient == nullptr) {
return Result::NOT_INITIALIZED;
}
- if (mDemux != nullptr) {
- return Result::SUCCESS;
- }
- Result res;
- uint32_t id;
- sp<IDemux> demuxSp;
- mTuner->openDemux([&](Result r, uint32_t demuxId, const sp<IDemux>& demux) {
- demuxSp = demux;
- id = demuxId;
- res = r;
- ALOGD("open demux, id = %d", demuxId);
- });
- if (res == Result::SUCCESS) {
- mDemux = demuxSp;
- mDemuxId = id;
- if (mFe != NULL) {
- mDemux->setFrontendDataSource(mFeId);
+
+ Result res = Result::SUCCESS;
+
+ if (mDemux == nullptr) {
+ uint32_t id;
+ sp<IDemux> demuxSp;
+ mTuner->openDemux([&](Result r, uint32_t demuxId, const sp<IDemux>& demux) {
+ demuxSp = demux;
+ id = demuxId;
+ res = r;
+ ALOGD("open demux, id = %d", demuxId);
+ });
+ if (res == Result::SUCCESS) {
+ mDemux = demuxSp;
+ mDemuxId = id;
+ if (mFe != NULL) {
+ mDemux->setFrontendDataSource(mFeId);
+ }
+ } else {
+ return res;
}
}
+
+ // TODO: replace demux opening with mTunerClient->openDemux(handle)
+ // when DemuxClient is fully ready
+ if (mDemuxClient == nullptr) {
+ sp<DemuxClient> demuxClient = new DemuxClient();
+ if (demuxClient == NULL) {
+ ALOGE("Failed to open demux");
+ return Result::UNKNOWN_ERROR;
+ }
+ mDemuxClient = demuxClient;
+ mDemuxClient->setHidlDemux(mDemux);
+ if (mFeClient != NULL) {
+ mDemuxClient->setFrontendDataSource(mFeClient);
+ }
+ }
+
return res;
}
@@ -1701,23 +1706,31 @@
return (jint) res;
}
}
+
+ if (mFeClient != NULL) {
+ res = mFeClient->close();
+ if (res != Result::SUCCESS) {
+ return (jint) res;
+ }
+ mFeClient = NULL;
+ }
+ if (mDemuxClient != NULL) {
+ res = mDemuxClient->close();
+ if (res != Result::SUCCESS) {
+ return (jint) res;
+ }
+ mDemuxClient = NULL;
+ }
return (jint) res;
}
-jobject JTuner::getAvSyncHwId(sp<Filter> filter) {
- if (mDemux == NULL) {
+jobject JTuner::getAvSyncHwId(sp<FilterClient> filterClient) {
+ if (mDemuxClient == NULL) {
return NULL;
}
- uint32_t avSyncHwId;
- Result res;
- sp<IFilter> iFilterSp = filter->getIFilter();
- mDemux->getAvSyncHwId(iFilterSp,
- [&](Result r, uint32_t id) {
- res = r;
- avSyncHwId = id;
- });
- if (res == Result::SUCCESS) {
+ int avSyncHwId = mDemuxClient->getAvSyncHwId(filterClient);
+ if (avSyncHwId >= 0) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
jclass integerClazz = env->FindClass("java/lang/Integer");
jmethodID intInit = env->GetMethodID(integerClazz, "<init>", "(I)V");
@@ -1727,17 +1740,11 @@
}
jobject JTuner::getAvSyncTime(jint id) {
- if (mDemux == NULL) {
+ if (mDemuxClient == NULL) {
return NULL;
}
- uint64_t time;
- Result res;
- mDemux->getAvSyncTime(static_cast<uint32_t>(id),
- [&](Result r, uint64_t ts) {
- res = r;
- time = ts;
- });
- if (res == Result::SUCCESS) {
+ long time = mDemuxClient->getAvSyncTime((int)id);
+ if (time >= 0) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
jclass longClazz = env->FindClass("java/lang/Long");
jmethodID longInit = env->GetMethodID(longClazz, "<init>", "(J)V");
@@ -1747,13 +1754,13 @@
}
int JTuner::connectCiCam(jint id) {
- if (mDemux == NULL) {
+ if (mDemuxClient == NULL) {
Result r = openDemux();
if (r != Result::SUCCESS) {
return (int) r;
}
}
- Result r = mDemux->connectCiCam(static_cast<uint32_t>(id));
+ Result r = mDemuxClient->connectCiCam((int)id);
return (int) r;
}
@@ -1779,13 +1786,13 @@
}
int JTuner::disconnectCiCam() {
- if (mDemux == NULL) {
+ if (mDemuxClient == NULL) {
Result r = openDemux();
if (r != Result::SUCCESS) {
return (int) r;
}
}
- Result r = mDemux->disconnectCiCam();
+ Result r = mDemuxClient->disconnectCiCam();
return (int) r;
}
@@ -1832,34 +1839,25 @@
}
jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) {
- if (mDemux == NULL) {
+ if (mDemux == NULL || mDemuxClient == NULL) {
if (openDemux() != Result::SUCCESS) {
return NULL;
}
}
- sp<IFilter> iFilterSp;
- sp<::android::hardware::tv::tuner::V1_1::IFilter> iFilterSp_1_1;
- sp<FilterCallback> callback = new FilterCallback();
- Result res;
- mDemux->openFilter(type, bufferSize, callback,
- [&](Result r, const sp<IFilter>& filter) {
- iFilterSp = filter;
- res = r;
- });
- if (res != Result::SUCCESS || iFilterSp == NULL) {
+ sp<FilterClient> filterClient;
+ sp<FilterClientCallbackImpl> callback = new FilterClientCallbackImpl();
+ filterClient = mDemuxClient->openFilter(type, bufferSize, callback);
+ if (filterClient == NULL) {
ALOGD("Failed to open filter, type = %d", type.mainType);
return NULL;
}
uint64_t fId;
- iFilterSp->getId([&](Result, uint32_t filterId) {
- fId = filterId;
- });
- iFilterSp_1_1 = ::android::hardware::tv::tuner::V1_1::IFilter::castFrom(iFilterSp);
- if (iFilterSp_1_1 != NULL) {
- iFilterSp_1_1->getId64Bit([&](Result, uint64_t filterId64Bit) {
- fId = filterId64Bit;
- });
+ Result res = filterClient->getId64Bit(fId);
+ if (res != Result::SUCCESS) {
+ uint32_t id;
+ filterClient->getId(id);
+ fId = static_cast<uint64_t>(id);
}
JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -1869,35 +1867,9 @@
gFields.filterInitID,
(jlong) fId);
- sp<Filter> filterSp = new Filter(iFilterSp, filterObj);
- filterSp->incStrong(filterObj);
- env->SetLongField(filterObj, gFields.filterContext, (jlong)filterSp.get());
- filterSp->mIsMediaFilter = false;
- filterSp->mAvSharedHandle = NULL;
- callback->setFilter(filterSp);
-
- if (type.mainType == DemuxFilterMainType::MMTP) {
- if (type.subType.mmtpFilterType() == DemuxMmtpFilterType::AUDIO ||
- type.subType.mmtpFilterType() == DemuxMmtpFilterType::VIDEO) {
- filterSp->mIsMediaFilter = true;
- }
- }
-
- if (type.mainType == DemuxFilterMainType::TS) {
- if (type.subType.tsFilterType() == DemuxTsFilterType::AUDIO ||
- type.subType.tsFilterType() == DemuxTsFilterType::VIDEO) {
- filterSp->mIsMediaFilter = true;
- }
- }
-
- if (iFilterSp_1_1 != NULL && filterSp->mIsMediaFilter) {
- iFilterSp_1_1->getAvSharedHandle([&](Result r, hidl_handle avMemory, uint64_t avMemSize) {
- if (r == Result::SUCCESS) {
- filterSp->mAvSharedHandle = native_handle_clone(avMemory.getNativeHandle());
- filterSp->mAvSharedMemSize = avMemSize;
- }
- });
- }
+ filterClient->incStrong(filterObj);
+ env->SetLongField(filterObj, gFields.filterContext, (jlong)filterClient.get());
+ callback->setFilter(env->NewWeakGlobalRef(filterObj), filterClient);
return filterObj;
}
@@ -2616,6 +2588,15 @@
if (r == Result::SUCCESS) {
mFe = NULL;
mFe_1_1 = NULL;
+ } else {
+ return (jint) r;
+ }
+
+ if (mFeClient != NULL) {
+ r = mFeClient->close();
+ }
+ if (r == Result::SUCCESS) {
+ mFeClient = NULL;
}
return (jint) r;
}
@@ -2627,10 +2608,18 @@
}
if (r == Result::SUCCESS) {
mDemux = NULL;
+ } else {
+ return (jint) r;
+ }
+
+ if (mDemuxClient != NULL) {
+ r = mDemuxClient->close();
+ }
+ if (r == Result::SUCCESS) {
+ mDemuxClient = NULL;
}
return (jint) r;
}
-
} // namespace android
////////////////////////////////////////////////////////////////////////////////
@@ -3271,8 +3260,8 @@
return settingsExt1_1;
}
-static sp<Filter> getFilter(JNIEnv *env, jobject filter) {
- return (Filter *)env->GetLongField(filter, gFields.filterContext);
+static sp<FilterClient> getFilterClient(JNIEnv *env, jobject filter) {
+ return (FilterClient *)env->GetLongField(filter, gFields.filterContext);
}
static DvrSettings getDvrSettings(JNIEnv *env, jobject settings, bool isRecorder) {
@@ -3383,7 +3372,7 @@
static void android_media_tv_Tuner_native_setup(JNIEnv *env, jobject thiz) {
sp<JTuner> tuner = new JTuner(env, thiz);
- setTuner(env,thiz, tuner);
+ setTuner(env, thiz, tuner);
}
static jint android_media_tv_Tuner_native_get_tuner_version(JNIEnv *env, jobject thiz) {
@@ -3399,8 +3388,7 @@
static jobject android_media_tv_Tuner_open_frontend_by_handle(
JNIEnv *env, jobject thiz, jint handle) {
sp<JTuner> tuner = getTuner(env, thiz);
- uint32_t id = getResourceIdFromHandle(handle);
- return tuner->openFrontendById(id);
+ return tuner->openFrontendByHandle(handle);
}
static int android_media_tv_Tuner_tune(JNIEnv *env, jobject thiz, jint type, jobject settings) {
@@ -3446,13 +3434,13 @@
static jobject android_media_tv_Tuner_get_av_sync_hw_id(
JNIEnv *env, jobject thiz, jobject filter) {
- sp<Filter> filterSp = getFilter(env, filter);
- if (filterSp == NULL) {
- ALOGD("Failed to get sync ID. Filter not found");
+ sp<FilterClient> filterClient = getFilterClient(env, filter);
+ if (filterClient == NULL) {
+ ALOGD("Failed to get sync ID. Filter client not found");
return NULL;
}
sp<JTuner> tuner = getTuner(env, thiz);
- return tuner->getAvSyncHwId(filterSp);
+ return tuner->getAvSyncHwId(filterClient);
}
static jobject android_media_tv_Tuner_get_av_sync_time(JNIEnv *env, jobject thiz, jint id) {
@@ -3913,26 +3901,13 @@
}
static Result configureIpFilterContextId(
- JNIEnv *env, sp<IFilter> iFilterSp, jobject ipFilterConfigObj) {
+ JNIEnv *env, sp<FilterClient> filterClient, jobject ipFilterConfigObj) {
jclass clazz = env->FindClass(
"android/media/tv/tuner/filter/IpFilterConfiguration");
uint32_t cid = env->GetIntField(ipFilterConfigObj, env->GetFieldID(
clazz, "mIpFilterContextId", "I"));
- Result res = Result::SUCCESS;
- if (cid != static_cast<uint32_t>(Constant::INVALID_IP_FILTER_CONTEXT_ID)) {
- sp<::android::hardware::tv::tuner::V1_1::IFilter> iFilterSp_1_1;
- iFilterSp_1_1 = ::android::hardware::tv::tuner::V1_1::IFilter::castFrom(iFilterSp);
- if (iFilterSp_1_1 != NULL) {
- res = iFilterSp_1_1->configureIpCid(cid);
- if (res != Result::SUCCESS) {
- return res;
- }
- } else {
- ALOGW("configureIpCid is not supported with the current HAL implementation.");
- }
- }
- return res;
+ return filterClient->configureIpFilterContextId(cid);
}
static jint copyData(JNIEnv *env, std::unique_ptr<MQ>& mq, EventFlag* flag, jbyteArray buffer,
@@ -3975,21 +3950,20 @@
static jint android_media_tv_Tuner_configure_filter(
JNIEnv *env, jobject filter, int type, int subtype, jobject settings) {
ALOGD("configure filter type=%d, subtype=%d", type, subtype);
- sp<Filter> filterSp = getFilter(env, filter);
- sp<IFilter> iFilterSp = filterSp->getIFilter();
- if (iFilterSp == NULL) {
+ sp<FilterClient> filterClient = getFilterClient(env, filter);
+ if (filterClient == NULL) {
ALOGD("Failed to configure filter: filter not found");
return (jint) Result::NOT_INITIALIZED;
}
DemuxFilterSettings filterSettings = getFilterConfiguration(env, type, subtype, settings);
- Result res = iFilterSp->configure(filterSettings);
+ Result res = filterClient->configure(filterSettings);
if (res != Result::SUCCESS) {
return (jint) res;
}
if (static_cast<DemuxFilterMainType>(type) == DemuxFilterMainType::IP) {
- res = configureIpFilterContextId(env, iFilterSp, settings);
+ res = configureIpFilterContextId(env, filterClient, settings);
if (res != Result::SUCCESS) {
return (jint) res;
}
@@ -3997,49 +3971,19 @@
AvStreamType streamType;
if (isAvFilterSettings(filterSettings) && getAvStreamType(env, settings, streamType)) {
- sp<::android::hardware::tv::tuner::V1_1::IFilter> iFilterSp_1_1;
- iFilterSp_1_1 = ::android::hardware::tv::tuner::V1_1::IFilter::castFrom(iFilterSp);
- if (iFilterSp_1_1 != NULL) {
- res = iFilterSp_1_1->configureAvStreamType(streamType);
- } else {
- ALOGW("configureAvStreamType is not supported with the current HAL implementation.");
- }
- if (res != Result::SUCCESS) {
- return (jint) res;
- }
+ res = filterClient->configureAvStreamType(streamType);
}
-
- MQDescriptorSync<uint8_t> filterMQDesc;
- Result getQueueDescResult = Result::UNKNOWN_ERROR;
- if (filterSp->mFilterMQ == NULL) {
- iFilterSp->getQueueDesc(
- [&](Result r, const MQDescriptorSync<uint8_t>& desc) {
- filterMQDesc = desc;
- getQueueDescResult = r;
- ALOGD("getFilterQueueDesc");
- });
- if (getQueueDescResult == Result::SUCCESS) {
- filterSp->mFilterMQ = std::make_unique<MQ>(filterMQDesc, true);
- EventFlag::createEventFlag(
- filterSp->mFilterMQ->getEventFlagWord(), &(filterSp->mFilterMQEventFlag));
- }
- }
- return (jint) getQueueDescResult;
+ return (jint) res;
}
static jint android_media_tv_Tuner_get_filter_id(JNIEnv* env, jobject filter) {
- sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
- if (iFilterSp == NULL) {
- ALOGD("Failed to get filter ID: filter not found");
+ sp<FilterClient> filterClient = getFilterClient(env, filter);
+ if (filterClient == NULL) {
+ ALOGD("Failed to get filter ID: filter client not found");
return (int) Result::NOT_INITIALIZED;
}
- Result res;
uint32_t id;
- iFilterSp->getId(
- [&](Result r, uint32_t filterId) {
- res = r;
- id = filterId;
- });
+ Result res = filterClient->getId(id);
if (res != Result::SUCCESS) {
return (jint) Constant::INVALID_FILTER_ID;
}
@@ -4047,30 +3991,13 @@
}
static jlong android_media_tv_Tuner_get_filter_64bit_id(JNIEnv* env, jobject filter) {
- sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
- if (iFilterSp == NULL) {
- ALOGD("Failed to get filter ID: filter not found");
- return static_cast<jlong>(
- ::android::hardware::tv::tuner::V1_1::Constant64Bit::INVALID_FILTER_ID_64BIT);
+ sp<FilterClient> filterClient = getFilterClient(env, filter);
+ if (filterClient == NULL) {
+ ALOGD("Failed to get filter ID 64 bit: filter client not found");
+ return (int) Result::NOT_INITIALIZED;
}
-
- sp<::android::hardware::tv::tuner::V1_1::IFilter> iFilterSp_1_1;
- iFilterSp_1_1 = ::android::hardware::tv::tuner::V1_1::IFilter::castFrom(iFilterSp);
- Result res;
uint64_t id;
-
- if (iFilterSp_1_1 != NULL) {
- iFilterSp_1_1->getId64Bit(
- [&](Result r, uint64_t filterId64Bit) {
- res = r;
- id = filterId64Bit;
- });
- } else {
- ALOGW("getId64Bit is not supported with the current HAL implementation.");
- return static_cast<jlong>(
- ::android::hardware::tv::tuner::V1_1::Constant64Bit::INVALID_FILTER_ID_64BIT);
- }
-
+ Result res = filterClient->getId64Bit(id);
return (res == Result::SUCCESS) ?
static_cast<jlong>(id) : static_cast<jlong>(
::android::hardware::tv::tuner::V1_1::Constant64Bit::INVALID_FILTER_ID_64BIT);
@@ -4078,96 +4005,96 @@
static jint android_media_tv_Tuner_configure_monitor_event(
JNIEnv* env, jobject filter, int monitorEventType) {
- sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
- if (iFilterSp == NULL) {
- ALOGD("Failed to configure scrambling event: filter not found");
- return (jint) Result::NOT_INITIALIZED;
+ sp<FilterClient> filterClient = getFilterClient(env, filter);
+ if (filterClient == NULL) {
+ ALOGD("Failed to configure scrambling event: filter client not found");
+ return (int) Result::NOT_INITIALIZED;
}
-
- sp<::android::hardware::tv::tuner::V1_1::IFilter> iFilterSp_1_1;
- iFilterSp_1_1 = ::android::hardware::tv::tuner::V1_1::IFilter::castFrom(iFilterSp);
- Result res;
-
- if (iFilterSp_1_1 != NULL) {
- res = iFilterSp_1_1->configureMonitorEvent(monitorEventType);
- } else {
- ALOGW("configureScramblingEvent is not supported with the current HAL implementation.");
- return (jint) Result::INVALID_STATE;
- }
-
+ Result res = filterClient->configureMonitorEvent(monitorEventType);
return (jint) res;
}
static jint android_media_tv_Tuner_set_filter_data_source(
JNIEnv* env, jobject filter, jobject srcFilter) {
- sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
- if (iFilterSp == NULL) {
- ALOGD("Failed to set filter data source: filter not found");
- return (jint) Result::NOT_INITIALIZED;
+ sp<FilterClient> filterClient = getFilterClient(env, filter);
+ if (filterClient == NULL) {
+ ALOGD("Failed to set filter data source: filter client not found");
+ return (int) Result::NOT_INITIALIZED;
}
- Result r;
+ Result res;
if (srcFilter == NULL) {
- r = iFilterSp->setDataSource(NULL);
+ res = filterClient->setDataSource(NULL);
} else {
- sp<IFilter> srcSp = getFilter(env, srcFilter)->getIFilter();
- if (iFilterSp == NULL) {
+ sp<FilterClient> srcClient = getFilterClient(env, srcFilter);
+ if (srcClient == NULL) {
ALOGD("Failed to set filter data source: src filter not found");
return (jint) Result::INVALID_ARGUMENT;
}
- r = iFilterSp->setDataSource(srcSp);
+ res = filterClient->setDataSource(srcClient);
}
- return (jint) r;
+ return (jint) res;
}
static jint android_media_tv_Tuner_start_filter(JNIEnv *env, jobject filter) {
- sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
- if (iFilterSp == NULL) {
- ALOGD("Failed to start filter: filter not found");
- return (jint) Result::NOT_INITIALIZED;
+ sp<FilterClient> filterClient = getFilterClient(env, filter);
+ if (filterClient == NULL) {
+ ALOGD("Failed to start filter: filter client not found");
+ return (int) Result::NOT_INITIALIZED;
}
- Result r = iFilterSp->start();
- return (jint) r;
+ return (jint) filterClient->start();
}
static jint android_media_tv_Tuner_stop_filter(JNIEnv *env, jobject filter) {
- sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
- if (iFilterSp == NULL) {
- ALOGD("Failed to stop filter: filter not found");
- return (jint) Result::NOT_INITIALIZED;
+ sp<FilterClient> filterClient = getFilterClient(env, filter);
+ if (filterClient == NULL) {
+ ALOGD("Failed to stop filter: filter client not found");
+ return (int) Result::NOT_INITIALIZED;
}
- Result r = iFilterSp->stop();
- return (jint) r;
+ return (jint) filterClient->stop();
}
static jint android_media_tv_Tuner_flush_filter(JNIEnv *env, jobject filter) {
- sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
- if (iFilterSp == NULL) {
- ALOGD("Failed to flush filter: filter not found");
- return (jint) Result::NOT_INITIALIZED;
+ sp<FilterClient> filterClient = getFilterClient(env, filter);
+ if (filterClient == NULL) {
+ ALOGD("Failed to flush filter: filter client not found");
+ return (int) Result::NOT_INITIALIZED;
}
- Result r = iFilterSp->flush();
- return (jint) r;
+ return (jint) filterClient->flush();
}
static jint android_media_tv_Tuner_read_filter_fmq(
JNIEnv *env, jobject filter, jbyteArray buffer, jlong offset, jlong size) {
- sp<Filter> filterSp = getFilter(env, filter);
- if (filterSp == NULL) {
+ sp<FilterClient> filterClient = getFilterClient(env, filter);
+ if (filterClient == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
- "Failed to read filter FMQ: filter not found");
+ "Failed to read filter FMQ: filter client not found");
return 0;
}
- return copyData(env, filterSp->mFilterMQ, filterSp->mFilterMQEventFlag, buffer, offset, size);
+
+ jboolean isCopy;
+ jbyte *dst = env->GetByteArrayElements(buffer, &isCopy);
+ ALOGD("copyData, isCopy=%d", isCopy);
+ if (dst == nullptr) {
+ jniThrowRuntimeException(env, "Failed to GetByteArrayElements");
+ return 0;
+ }
+ int realReadSize = filterClient->read(reinterpret_cast<uint8_t*>(dst) + offset, size);
+ env->ReleaseByteArrayElements(buffer, dst, 0);
+ if (realReadSize < 0) {
+ return (jint) Result::UNKNOWN_ERROR;
+ }
+ return (jint) Result::SUCCESS;
}
static jint android_media_tv_Tuner_close_filter(JNIEnv *env, jobject filter) {
- sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
- if (iFilterSp == NULL) {
- ALOGD("Failed to close filter: filter not found");
- return (jint) Result::NOT_INITIALIZED;
+ sp<FilterClient> filterClient = getFilterClient(env, filter);
+ if (filterClient == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Failed to close filter: filter client not found");
+ return 0;
}
- Result r = iFilterSp->close();
- return (jint) r;
+
+ return (jint) filterClient->close();
}
static sp<TimeFilter> getTimeFilter(JNIEnv *env, jobject filter) {
@@ -4275,7 +4202,8 @@
if (descramblerSp == NULL) {
return (jint) Result::NOT_INITIALIZED;
}
- sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
+ // TODO: use filter client once descramblerClient is ready
+ sp<IFilter> iFilterSp = getFilterClient(env, filter)->getHalFilter();
Result result = descramblerSp->addPid(getDemuxPid((int)pidType, (int)pid), iFilterSp);
return (jint) result;
}
@@ -4286,7 +4214,8 @@
if (descramblerSp == NULL) {
return (jint) Result::NOT_INITIALIZED;
}
- sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
+ // TODO: use filter client once descramblerClient is ready
+ sp<IFilter> iFilterSp = getFilterClient(env, filter)->getHalFilter();
Result result = descramblerSp->removePid(getDemuxPid((int)pidType, (int)pid), iFilterSp);
return (jint) result;
}
@@ -4358,12 +4287,13 @@
if (dvrSp == NULL) {
return (jint) Result::NOT_INITIALIZED;
}
- sp<Filter> filterSp = getFilter(env, filter);
- if (filterSp == NULL) {
+ sp<FilterClient> filterClient = getFilterClient(env, filter);
+ if (filterClient == NULL) {
return (jint) Result::INVALID_ARGUMENT;
}
sp<IDvr> iDvrSp = dvrSp->getIDvr();
- sp<IFilter> iFilterSp = filterSp->getIFilter();
+ // TODO: use filter client once dvrClient is ready
+ sp<IFilter> iFilterSp = filterClient->getHalFilter();
Result result = iDvrSp->attachFilter(iFilterSp);
return (jint) result;
}
@@ -4373,12 +4303,13 @@
if (dvrSp == NULL) {
return (jint) Result::NOT_INITIALIZED;
}
- sp<Filter> filterSp = getFilter(env, filter);
- if (filterSp == NULL) {
+ sp<FilterClient> filterClient = getFilterClient(env, filter);
+ if (filterClient == NULL) {
return (jint) Result::INVALID_ARGUMENT;
}
sp<IDvr> iDvrSp = dvrSp->getIDvr();
- sp<IFilter> iFilterSp = filterSp->getIFilter();
+ // TODO: use filter client once dvrClient is ready
+ sp<IFilter> iFilterSp = filterClient->getHalFilter();
Result result = iDvrSp->detachFilter(iFilterSp);
return (jint) result;
}
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index bec834c..4149228 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -34,6 +34,11 @@
#include <utils/Mutex.h>
#include <utils/RefBase.h>
+#include "tuner/DemuxClient.h"
+#include "tuner/FilterClient.h"
+#include "tuner/FilterClientCallback.h"
+#include "tuner/FrontendClient.h"
+#include "tuner/FrontendClientCallback.h"
#include "tuner/TunerClient.h"
#include "jni.h"
@@ -95,6 +100,7 @@
Lnb(sp<ILnb> sp, jobject obj);
~Lnb();
sp<ILnb> getILnb();
+ // TODO: remove after migrate to client lib
sp<ILnb> mLnbSp;
jweak mLnbObj;
};
@@ -115,6 +121,7 @@
jint close();
MQ& getDvrMQ();
sp<IDvr> getIDvr();
+ // TODO: remove after migrate to client lib
sp<IDvr> mDvrSp;
jweak mDvrObj;
std::unique_ptr<MQ> mDvrMQ;
@@ -123,29 +130,15 @@
int mFd;
};
-struct Filter : public RefBase {
- Filter(sp<IFilter> sp, jobject obj);
- ~Filter();
- int close();
- sp<IFilter> getIFilter();
- sp<IFilter> mFilterSp;
- std::unique_ptr<MQ> mFilterMQ;
- EventFlag* mFilterMQEventFlag;
- jweak mFilterObj;
- native_handle_t* mAvSharedHandle;
- uint64_t mAvSharedMemSize;
- bool mIsMediaFilter;
-};
-
struct MediaEvent : public RefBase {
- MediaEvent(sp<Filter> filter, hidl_handle avHandle, uint64_t dataId,
+ MediaEvent(sp<FilterClient> filterClient, hidl_handle avHandle, uint64_t dataId,
uint64_t dataSize, jobject obj);
~MediaEvent();
jobject getLinearBlock();
uint64_t getAudioHandle();
void finalize();
- sp<Filter> mFilter;
+ sp<FilterClient> mFilterClient;
native_handle_t* mAvHandle;
uint64_t mDataId;
uint64_t mDataSize;
@@ -159,16 +152,16 @@
std::weak_ptr<C2Buffer> mC2Buffer;
};
-struct FilterCallback : public IFilterCallback {
- ~FilterCallback();
- virtual Return<void> onFilterEvent_1_1(const DemuxFilterEvent& filterEvent,
+struct FilterClientCallbackImpl : public FilterClientCallback {
+ virtual void onFilterEvent_1_1(const DemuxFilterEvent& filterEvent,
const DemuxFilterEventExt& filterEventExt);
- virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent);
- virtual Return<void> onFilterStatus(const DemuxFilterStatus status);
+ virtual void onFilterEvent(const DemuxFilterEvent& filterEvent);
+ virtual void onFilterStatus(const DemuxFilterStatus status);
- void setFilter(const sp<Filter> filter);
+ void setFilter(jweak filterObj, sp<FilterClient> filterClient);
private:
- sp<Filter> mFilter;
+ jweak mFilterObj;
+ sp<FilterClient> mFilterClient;
jobjectArray getSectionEvent(
jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
jobjectArray getMediaEvent(
@@ -195,13 +188,13 @@
jobjectArray& arr, const std::vector<DemuxFilterEventExt::Event>& eventsExt);
};
-struct FrontendCallback : public IFrontendCallback {
- FrontendCallback(jweak tunerObj, FrontendId id);
+struct FrontendClientCallbackImpl : public FrontendClientCallback {
+ FrontendClientCallbackImpl(jweak tunerObj, FrontendId id);
- virtual Return<void> onEvent(FrontendEventType frontendEventType);
- virtual Return<void> onScanMessage(
+ virtual void onEvent(FrontendEventType frontendEventType);
+ virtual void onScanMessage(
FrontendScanMessageType type, const FrontendScanMessage& message);
- virtual Return<void> onScanMessageExt1_1(
+ virtual void onScanMessageExt1_1(
FrontendScanMessageTypeExt1_1 type, const FrontendScanMessageExt1_1& messageExt);
jweak mObject;
@@ -212,22 +205,24 @@
TimeFilter(sp<ITimeFilter> sp, jweak obj);
~TimeFilter();
sp<ITimeFilter> getITimeFilter();
+ // TODO: remove after migrate to client lib
sp<ITimeFilter> mTimeFilterSp;
jweak mTimeFilterObj;
};
struct JTuner : public RefBase {
JTuner(JNIEnv *env, jobject thiz);
+ // TODO: modify after migrate to client lib
sp<ITuner> getTunerService();
int getTunerVersion();
- jobject getAvSyncHwId(sp<Filter> filter);
+ jobject getAvSyncHwId(sp<FilterClient> filter);
jobject getAvSyncTime(jint id);
int connectCiCam(jint id);
int linkCiCam(jint id);
int disconnectCiCam();
int unlinkCiCam(jint id);
jobject getFrontendIds();
- jobject openFrontendById(int id);
+ jobject openFrontendByHandle(int feHandle);
jint closeFrontendById(int id);
jobject getFrontendInfo(int id);
int tune(const FrontendSettings& settings, const FrontendSettingsExt1_1& settingsExt1_1);
@@ -257,15 +252,22 @@
private:
jclass mClass;
jweak mObject;
+ // TODO: remove after migrate to client lib
static sp<ITuner> mTuner;
static sp<::android::hardware::tv::tuner::V1_1::ITuner> mTuner_1_1;
static sp<TunerClient> mTunerClient;
+ // TODO: remove after migrate to client lib
sp<IFrontend> mFe;
+ // TODO: remove after migrate to client lib
sp<::android::hardware::tv::tuner::V1_1::IFrontend> mFe_1_1;
+ sp<FrontendClient> mFeClient;
int mFeId;
hidl_vec<LnbId> mLnbIds;
+ // TODO: remove after migrate to client lib
sp<ILnb> mLnb;
+ // TODO: remove after migrate to client lib
sp<IDemux> mDemux;
+ sp<DemuxClient> mDemuxClient;
uint32_t mDemuxId;
static jobject getAnalogFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps);
static jobject getAtsc3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps);
@@ -279,6 +281,9 @@
static jobject getDtmbFrontendCaps(JNIEnv *env, int id);
bool isV1_1ExtendedStatusType(jint type);
+ static uint32_t getResourceIdFromHandle(jint handle) {
+ return (handle & 0x00ff0000) >> 16;
+ }
};
class C2DataIdInfo : public C2Param {
diff --git a/media/jni/tuner/DemuxClient.cpp b/media/jni/tuner/DemuxClient.cpp
index 11acb5e..b237a24 100644
--- a/media/jni/tuner/DemuxClient.cpp
+++ b/media/jni/tuner/DemuxClient.cpp
@@ -68,14 +68,12 @@
sp<HidlFilterCallback> callback = new HidlFilterCallback(cb);
sp<IFilter> hidlFilter = openHidlFilter(type, bufferSize, callback);
if (hidlFilter != NULL) {
- sp<FilterClient> filterClient = new FilterClient();
+ sp<FilterClient> filterClient = new FilterClient(type);
filterClient->setHidlFilter(hidlFilter);
return filterClient;
}
}
- // TODO: handle share av memory handle
-
return NULL;
}
@@ -141,7 +139,7 @@
}
Result DemuxClient::close() {
- // pending aidl interface
+ // TODO: pending aidl interface
if (mDemux != NULL) {
Result res = mDemux->close();
diff --git a/media/jni/tuner/FilterClient.cpp b/media/jni/tuner/FilterClient.cpp
index a71cae60..0aab5fe 100644
--- a/media/jni/tuner/FilterClient.cpp
+++ b/media/jni/tuner/FilterClient.cpp
@@ -22,6 +22,9 @@
#include "FilterClient.h"
using ::android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
+using ::android::hardware::tv::tuner::V1_0::DemuxMmtpFilterType;
+using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
namespace android {
@@ -29,20 +32,25 @@
// TODO: pending aidl interface
// TODO: add filter callback
-FilterClient::FilterClient() {
+FilterClient::FilterClient(DemuxFilterType type) {
//mTunerFilter = tunerFilter;
+ mAvSharedHandle = NULL;
+ checkIsMediaFilter(type);
}
FilterClient::~FilterClient() {
//mTunerFilter = NULL;
mFilter = NULL;
mFilter_1_1 = NULL;
+ mAvSharedHandle = NULL;
+ mAvSharedMemSize = 0;
}
// TODO: remove after migration to Tuner Service is done.
void FilterClient::setHidlFilter(sp<IFilter> filter) {
mFilter = filter;
mFilter_1_1 = ::android::hardware::tv::tuner::V1_1::IFilter::castFrom(mFilter);
+ handleAvShareMemory();
}
int FilterClient::read(uint8_t* buffer, int size) {
@@ -59,6 +67,22 @@
return -1;
}
+SharedHandleInfo FilterClient::getAvSharedHandleInfo() {
+ SharedHandleInfo info{
+ .sharedHandle = NULL,
+ .size = 0,
+ };
+
+ // TODO: pending aidl interface
+
+ if (mFilter_1_1 != NULL) {
+ info.sharedHandle = mAvSharedHandle;
+ info.size = mAvSharedMemSize;
+ }
+
+ return info;
+}
+
Result FilterClient::configure(DemuxFilterSettings configure) {
// TODO: pending aidl interface
@@ -187,7 +211,11 @@
// TODO: pending aidl interface
if (mFilter != NULL) {
- return mFilter->close();
+ Result res = mFilter->close();
+ if (res == Result::SUCCESS) {
+ mFilter = NULL;
+ }
+ return res;
}
return Result::INVALID_STATE;
@@ -261,4 +289,31 @@
return size;
}
+
+void FilterClient::checkIsMediaFilter(DemuxFilterType type) {
+ if (type.mainType == DemuxFilterMainType::MMTP) {
+ if (type.subType.mmtpFilterType() == DemuxMmtpFilterType::AUDIO ||
+ type.subType.mmtpFilterType() == DemuxMmtpFilterType::VIDEO) {
+ mIsMediaFilter = true;
+ }
+ }
+
+ if (type.mainType == DemuxFilterMainType::TS) {
+ if (type.subType.tsFilterType() == DemuxTsFilterType::AUDIO ||
+ type.subType.tsFilterType() == DemuxTsFilterType::VIDEO) {
+ mIsMediaFilter = true;
+ }
+ }
+}
+
+void FilterClient::handleAvShareMemory() {
+ if (mFilter_1_1 != NULL && mIsMediaFilter) {
+ mFilter_1_1->getAvSharedHandle([&](Result r, hidl_handle avMemory, uint64_t avMemSize) {
+ if (r == Result::SUCCESS) {
+ mAvSharedHandle = native_handle_clone(avMemory.getNativeHandle());
+ mAvSharedMemSize = avMemSize;
+ }
+ });
+ }
+}
} // namespace android
diff --git a/media/jni/tuner/FilterClient.h b/media/jni/tuner/FilterClient.h
index 4af74b0..976b2f5 100644
--- a/media/jni/tuner/FilterClient.h
+++ b/media/jni/tuner/FilterClient.h
@@ -34,6 +34,7 @@
using ::android::hardware::Void;
using ::android::hardware::hidl_handle;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterType;
using ::android::hardware::tv::tuner::V1_0::IFilter;
using ::android::hardware::tv::tuner::V1_0::Result;
using ::android::hardware::tv::tuner::V1_1::AvStreamType;
@@ -45,6 +46,11 @@
namespace android {
+struct SharedHandleInfo {
+ native_handle_t* sharedHandle;
+ uint64_t size;
+};
+
// TODO: pending aidl interface
/*class TunerFilterCallback : public BnTunerFilterCallback {
@@ -75,7 +81,7 @@
public:
// TODO: pending aidl interface
- FilterClient();
+ FilterClient(DemuxFilterType type);
~FilterClient();
// TODO: remove after migration to Tuner Service is done.
@@ -89,6 +95,11 @@
int read(uint8_t* buffer, int size);
/**
+ * Get the a/v shared memory handle information
+ */
+ SharedHandleInfo getAvSharedHandleInfo();
+
+ /**
* Configure the filter.
*/
Result configure(DemuxFilterSettings configure);
@@ -161,6 +172,8 @@
private:
Result getFilterMq();
int copyData(uint8_t* buffer, int size);
+ void checkIsMediaFilter(DemuxFilterType type);
+ void handleAvShareMemory();
/**
* An AIDL Tuner Filter Singleton assigned at the first time when the Tuner Client
@@ -189,6 +202,10 @@
sp<FilterClientCallback> mCallback;
//shared_ptr<TunerFilterCallback> mAidlCallback;
sp<HidlFilterCallback> mHidlCallback;
+
+ native_handle_t* mAvSharedHandle;
+ uint64_t mAvSharedMemSize;
+ bool mIsMediaFilter;
};
} // namespace android
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 6db4da9..3daaf05 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -103,7 +103,7 @@
version_script: "libandroid.map.txt",
stubs: {
symbol_file: "libandroid.map.txt",
- versions: ["29"],
+ versions: ["29", "31"],
},
}
diff --git a/native/android/OWNERS b/native/android/OWNERS
index 266764a..ac5a895 100644
--- a/native/android/OWNERS
+++ b/native/android/OWNERS
@@ -1,4 +1,3 @@
-set noparent
-
+per-file libandroid_net.map.txt, net.c = set noparent
per-file libandroid_net.map.txt, net.c = codewiz@google.com, jchalard@google.com, junyulai@google.com
per-file libandroid_net.map.txt, net.c = lorenzo@google.com, reminv@google.com, satk@google.com
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 438e8b8..c2b26bc 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Ignoreer kodewisselingverstekke"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Aktiveer kodewisseling"</string>
<string name="transcode_default" msgid="3784803084573509491">"Aanvaar dat programme moderne formate steun"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Aktiveer kodewisseling vir programme"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Lopende dienste"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Sien en beheer dienste wat tans aktief is"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Bedraade oorfoon"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aan"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Af"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Diensverskaffernetwerk verander tans"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobiele data is af"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Nie gestel om data te gebruik nie"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Geen foon nie."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Foon, een staaf."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Foon, twee stawe."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Foon, drie stawe."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Foonsein is vol."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Geen data nie."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data, een staaf."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data, twee stawe."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data, drie stawe."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Datasein vol."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet is ontkoppel."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet gekoppel."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index fd5777d..65ce6e0 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"የትራንስኮዲንግ ነባሪዎችን ሻር"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"ትራንስኮዲንግን ያንቁ"</string>
<string name="transcode_default" msgid="3784803084573509491">"መተግበሪያዎች ዘመናዊ ቅርጸቶችን እንደሚደግፉ አድርገው ይቁጠሩ"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"ለመተግበሪያዎች ትራንስኮዲንግን ያንቁ"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"አሂድ አገልግሎቶች"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"በአሁኑጊዜ እየሄዱ ያሉ አገልግሎቶችን ተቆጣጠር እና እይ"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"የWebView ትግበራ"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ባለገመድ ጆሮ ማዳመጫ"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"አብራ"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"አጥፋ"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"የአገልግሎት አቅራቢ አውታረ መረብን በመቀየር ላይ"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3ጂ"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"ኤጅ"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"ጂፒአርኤስ"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"ሰ"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"ሰ+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4ጂ"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"የተንቀሳቃሽ ስልክ ውሂብ ጠፍቷል"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"ውሂብን ለመጠቀም አልተቀናበረም"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"ምንም ስልክ የለም።"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"የስልክ አንድ አሞሌ"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"የስልክ ሁለት አሞሌ"</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"የስልክ ሦስት አሞሌ"</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"የስልክ አመልካች ሙሉ ነው።"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"ምንም ውሂብ የለም።"</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"የውሂብ አንድ አሞሌ"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"የውሂብ ሁለት አሞሌዎች።"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"የውሂብ ሦስት አሞሌዎች።"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"የውሂብ አመልካች ሙሉ ነው።"</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ኤተርኔት ተነቅሏል።"</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ኤተርኔት ተገናኝቷል።"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index b81031e..3ea96c7 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"إلغاء الإعدادات التلقائية لتحويل الترميز"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"تفعيل تحويل الترميز"</string>
<string name="transcode_default" msgid="3784803084573509491">"افتراض أن التطبيق يتوافق مع التنسيقات الحديثة"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"تفعيل تحويل الترميز للتطبيقات"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"الخدمات قيد التشغيل"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"عرض الخدمات قيد التشغيل في الوقت الحالي والتحكم فيها"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"تطبيق WebView"</string>
@@ -570,4 +569,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"سمّاعة سلكية"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"تفعيل"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"إيقاف"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"جارٍ تغيير شبكة مشغِّل شبكة الجوّال."</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"شبكة الجيل الثالث"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"شبكة EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"شبكة GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"شبكة الجيل الرابع"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"شبكة الجيل الرابع أو أحدث"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"تم إيقاف بيانات الجوال"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"لم يتم الضبط على استخدام البيانات"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"ليست هناك إشارة بالهاتف."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"إشارة الهاتف تتكون من شريط واحد."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"إشارة الهاتف تتكون من شريطين."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"إشارة الهاتف تتكون من ثلاثة أشرطة."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"إشارة الهاتف كاملة."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"لا تتوفر بيانات."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"إشارة البيانات تتكون من شريط واحد."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"إشارة البيانات تتكون من شريطين."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"إشارة البيانات تتكون من ثلاثة أشرطة."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"إشارة البيانات كاملة."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"تم قطع اتصال Ethernet."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"تم إنشاء اتصال Ethernet."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index e482329..a259687 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ট্ৰেন্সক’ডিং ডিফ’ল্ট অ’ভাৰৰাইড কৰক"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"ট্ৰেন্সক’ডিং সক্ষম কৰক"</string>
<string name="transcode_default" msgid="3784803084573509491">"এপে আধুনিক ফৰ্মেট সমৰ্থন কৰে বুলি ধৰি লওক"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"এপৰ বাবে ট্ৰান্সক\'ডিং সক্ষম কৰক"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"চলিত সেৱা"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"বৰ্তমান চলি থকা সেৱাসমূহ চাওক আৰু নিয়ন্ত্ৰণ কৰক"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"ৱেবভিউ প্ৰয়োগ"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"তাঁৰযুক্ত হেডফ\'ন"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"অন"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"অফ"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"বাহক নেটৱৰ্কৰ পৰিৱৰ্তন"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"জিপিআৰএছ"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"এলটিই"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"এলটিই+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"ম’বাইল ডেটা অফ অৱস্থাত আছে"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"ডেটা ব্যৱহাৰ কৰিবলৈ ছেট কৰা নাই"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"ফ\'নত ছিগনেল নাই৷"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"ফ\'ন ছিগনেলৰ এডাল দণ্ড।"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"ফ\'ন ছিগনেলৰ দুডাল দণ্ড।"</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"ফ\'নৰ ছিগনেলৰ তিনিডাল দণ্ড আছে।"</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"ফ\'নৰ ছিগনেল পূৰা আছে৷"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"কোনো ডেটা নাই।"</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"ডেটা ছিগনেলৰ এডাল দণ্ড।"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"ডেটা ছংনেলৰ তিনিডাল দণ্ড।"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"ডেটা ছিংগনেলত তিনিডাল দণ্ড আছে।"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"ডেটা ছিগনেল পূৰা আছে।"</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ইথাৰনেট সংযোগ বিচ্ছিন্ন হৈছে।"</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ইথাৰনেট সংযোগ হৈছে।"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 637785d..2cbd681 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Yenidən kodlaşdırma defoltlarını əvəzləyin"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Yenidən kodlaşdırmanı aktiv edin"</string>
<string name="transcode_default" msgid="3784803084573509491">"Tətbiqlərin müasir formatları dəstəklədiyini qəbul edin"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Tətbiqlər üçün yenidən kodlaşdırmanı aktiv edin"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"İşləyən xidmətlər"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Hazırda prosesdə olan xidmətləri görüntüləyin və onlara nəzarət edin"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView icrası"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Simli qulaqlıq"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktiv"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Deaktiv"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator şəbəkəsinin dəyişilməsi"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobil data deaktivdir"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Data istifadə etmək üçün ayarlanmayıb"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Telefon yoxdur."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Şəbəkə bir xətdir."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Şəbəkə iki xətdir."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Şəbəkə üç xətdir."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Tam şəbəkə."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Məlumat yoxdur."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data bir xətdir."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data iki xətdir."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data üç xətdir."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Data siqnalı tamdır."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet bağlantısı kəsilib."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet qoşuludur."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 219d5a0..4d8e348 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Zameni podrazumevana podešavanja transkodiranja"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Omogući transkodiranje"</string>
<string name="transcode_default" msgid="3784803084573509491">"Podrazumevaj da aplikacije podržavaju moderne formate"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Omogućite transkodiranje za aplikacije"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Pokrenute usluge"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Prikaz i kontrola trenutno pokrenutih usluga"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Primena WebView-a"</string>
@@ -567,4 +566,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žičane slušalice"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Uključeno"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Isključeno"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Promena mreže mobilnog operatera"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobilni podaci su isključeni"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Nije podešeno za korišćenje podataka"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Nema telefona."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Signal telefona ima jednu crtu."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Signal telefona od dve crte."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Signal telefona od tri crte."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Signal telefona je pun."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Nema podataka."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Signal za podatke ima jednu crtu."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Signal za podatke od dve crte."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Signal za podatke od tri crte."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Signal za podatke je najjači."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Veza sa eternetom je prekinuta."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Eternet je povezan."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 4772e03..4d6f3ac 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -400,13 +400,9 @@
<string name="inactive_app_active_summary" msgid="8047630990208722344">"Актыўная. Краніце, каб пераключыць."</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"Стан праграмы ў рэжыме чакання: <xliff:g id="BUCKET"> %s</xliff:g>"</string>
<string name="transcode_settings_title" msgid="2581975870429850549">"Налады перакадзіравання мультымедыя"</string>
- <!-- no translation found for transcode_user_control (6176368544817731314) -->
- <skip />
- <!-- no translation found for transcode_enable_all (2411165920039166710) -->
- <skip />
- <!-- no translation found for transcode_default (3784803084573509491) -->
- <skip />
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Уключыць перакадзіраванне для праграм"</string>
+ <string name="transcode_user_control" msgid="6176368544817731314">"Перавызначыць стандартныя налады перакадзіравання"</string>
+ <string name="transcode_enable_all" msgid="2411165920039166710">"Уключыць перакадзіраванне"</string>
+ <string name="transcode_default" msgid="3784803084573509491">"Лічыца, што праграмы падтрымліваюць сучасныя фарматы"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Запушчаныя службы"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Прагляд запушчаных службаў i кіраванне iмi"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Рэалізацыя WebView"</string>
@@ -571,4 +567,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Правадныя навушнікі"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Уключана"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Выключана"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Змяненне аператара сеткі"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Мабільная перадача даных выключана"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Не зададзена для выкарыстання даных"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Няма тэлефона."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Адна планка на тэлефоне."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"2 планкі тэлефона."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"3 планкі тэлефона."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Поўны сігнал тэлефона."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Няма дадзеных."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Адна планка дадзеных."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"2 планкі дадзеных."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"3 планкі дадзеных."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Поўны сігнал перадачы дадзеных."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet адлучаны."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet падлучаны."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 75d1eeb..ef0412b 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Отмяна на стандартните настройки за прекодирането"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Активиране на прекодирането"</string>
<string name="transcode_default" msgid="3784803084573509491">"Предполагане, че приложенията поддържат съвременни формати"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Активиране на прекодирането за приложения"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Изпълнявани услуги"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Преглед и контрол върху изпълняващите се понастоящем услуги"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Внедряване на WebView"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Слушалки с кабел"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Включване"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Изключване"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Промяна на мрежата на оператора"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Мобилните данни са изключени"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Не е зададено да използва данни"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Няма телефон."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Телефонът е с една чертичка."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Телефонът е с две чертички."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Телефонът е с три чертички."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Сигналът за телефона е пълен."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Няма данни."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Данните са с една чертичка."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Данните са с две чертички."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Данните са с три чертички."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Сигналът за данни е пълен."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Връзката с Ethernet е прекратена."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Установена е връзка с Ethernet."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 325f2bd..5b95399 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -400,13 +400,9 @@
<string name="inactive_app_active_summary" msgid="8047630990208722344">"সক্রিয় রয়েছে৷ টগল করতে আলতো চাপুন৷"</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"অ্যাপ স্ট্যান্ডবাই-এর অবস্থা:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
<string name="transcode_settings_title" msgid="2581975870429850549">"মিডিয়া ট্রান্সকোডিং সেটিংস"</string>
- <!-- no translation found for transcode_user_control (6176368544817731314) -->
- <skip />
- <!-- no translation found for transcode_enable_all (2411165920039166710) -->
- <skip />
- <!-- no translation found for transcode_default (3784803084573509491) -->
- <skip />
- <string name="transcode_skip_apps" msgid="8249721984597390142">"অ্যাপের জন্য ট্রান্সকোডিং চালু করুন"</string>
+ <string name="transcode_user_control" msgid="6176368544817731314">"ট্রান্সকোডিং ডিফল্ট সেটিংস ওভাররাইড করুন"</string>
+ <string name="transcode_enable_all" msgid="2411165920039166710">"ট্রান্সকোডিং চালু করুন"</string>
+ <string name="transcode_default" msgid="3784803084573509491">"অ্যাপ মর্ডার্ন ফর্ম্যাটে কাজ করবে বলে ধরে নিন"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"এখন চলছে যে পরিষেবাগুলি"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"বর্তমান চলমান পরিষেবাগুলি দেখুন এবং নিয়ন্ত্রণ করুন"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"ওয়েবভিউ প্রয়োগ"</string>
@@ -569,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"তার যুক্ত হেডফোন"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"চালু আছে"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"বন্ধ আছে"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"পরিষেবা প্রদানকারীর নেটওয়ার্ক পরিবর্তন করা হচ্ছে"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"মোবাইল ডেটা বন্ধ করা হয়েছে"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"ডেটা ব্যবহার করার জন্য সেট করা নেই"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"কোনো ফোনের সংকেত নেই৷"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"এক দন্ড ফোনের সংকেত রয়েছে৷"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"দুই দন্ড ফোনের সংকেত রয়েছে৷"</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"তিন দন্ড ফোনের সংকেত রয়েছে৷"</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"ফোনের সংকেত পূর্ণ রয়েছে৷"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"কোনো ডেটা নেই৷"</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"এক দন্ড ডেটার সংকেত৷"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"দুই দন্ড ডেটার সংকেত রয়েছে৷"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"তিন দন্ড ডেটার সংকেত৷"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"পূর্ণ ডেটার সংকেত রয়েছে৷"</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ইথারনেটের সংযোগ বিচ্ছিন্ন হয়েছে৷"</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ইথারনেট সংযুক্ত হয়েছে৷"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index ab4ac14..00d8087 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Zaobiđi zadane postavke transkodiranja"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Omogući transkodiranje"</string>
<string name="transcode_default" msgid="3784803084573509491">"Pretpostavi da aplikacije podržavaju moderne formate"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Omogućite transkodiranje za aplikacije"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Pokrenute usluge"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Prikaz i kontrola trenutno pokrenutih usluga"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Postavljanje WebViewa"</string>
@@ -567,4 +566,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žičane slušalice"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Uključi"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Isključi"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Promjena mreže mobilnog operatera"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Prijenos podataka na mobilnoj mreži je isključen"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Nije postavljeno za korištenje podataka"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Nema telefonskog signala."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefonski signal na jednoj crtici."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefonski signal na dvije crtice."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefonski signal na tri crtice."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefonski signal pun."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Nema podataka."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Prijenos podataka na jednoj crtici."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Prijenos podataka na dvije crtice."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Prijenos podataka na tri crtice."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Signal za prijenos podataka pun."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Veza sa Ethernetom je prekinuta."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet je spojen."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 9bb919f..300b475 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Substitueix els valors predeterminats de la transcodificació"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Activa la transcodificació"</string>
<string name="transcode_default" msgid="3784803084573509491">"Assumeix que les aplicacions són compatibles amb formats moderns"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Activa la transcodificació per a les aplicacions"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Serveis en execució"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Visualitza i controla els serveis en execució"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementació de WebView"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculars amb cable"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activa"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactiva"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"S\'està canviant la xarxa de l\'operador de telefonia mòbil"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"S\'han desactivat les dades mòbils"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"No s\'ha definit per utilitzar dades"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"No hi ha senyal de telèfon."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Senyal de telèfon: una barra"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Senyal de telèfon: dues barres."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Senyal de telèfon: tres barres."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Senyal de telèfon: complet."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Senyal de dades: no n\'hi ha"</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Senyal de dades: una barra."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Senyal de dades: dues barres."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Senyal de dades: tres barres."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Senyal de dades: complet."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"S\'ha desconnectat l\'Ethernet."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet connectada"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 5f2e005..a9a5f48 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Přepsat výchozí nastavení překódování"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Povolit překódování"</string>
<string name="transcode_default" msgid="3784803084573509491">"Předpokládat, že aplikace podporují moderní formáty"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Povolit překódování pro aplikace"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Spuštěné služby"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Umožňuje zobrazit a ovládat aktuálně spuštěné služby"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementace WebView"</string>
@@ -568,4 +567,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kabelová sluchátka"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Zapnout"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Vypnout"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Probíhá změna sítě operátora"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobilní data jsou vypnuta"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Nenastaveno k využití dat"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Žádná telefonní síť."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Jedna čárka signálu telefonní sítě."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Dvě čárky signálu telefonní sítě."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Tři čárky signálu telefonní sítě."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Plný signál telefonní sítě."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Žádné datové připojení."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Jedna čárka signálu datové sítě."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Dvě čárky signálu datové sítě."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Tři čárky signálu datové sítě."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Plný signál datové sítě."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Síť ethernet je odpojena."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Síť ethernet je připojena."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index f4f4650..738ed3c 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Tilsidesæt standardindstillingerne for omkodning"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Aktivér omkodning"</string>
<string name="transcode_default" msgid="3784803084573509491">"Gå ud fra, at apps understøtter moderne formater"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Aktivér omkodning for apps"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Kørende tjenester"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Vis og administrer kørende tjenester"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Høretelefoner med ledning"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Til"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Fra"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Skift af mobilnetværk"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobildata er deaktiveret"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Ikke indstillet til at anvende data"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Ingen telefon."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefon en bjælke."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefon to bjælker."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefon tre bjælker."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefonsignal fuldt."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Ingen data."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data en bjælke."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data to bjælker."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data tre bjælker."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Datasignal fuldt."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet er ikke tilsluttet."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet er tilsluttet."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 1d6894b..e274d63 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -400,13 +400,9 @@
<string name="inactive_app_active_summary" msgid="8047630990208722344">"Aktiv. Zum Wechseln tippen."</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"Standby-Status der App:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
<string name="transcode_settings_title" msgid="2581975870429850549">"Einstellungen für Medientranscodierung"</string>
- <!-- no translation found for transcode_user_control (6176368544817731314) -->
- <skip />
- <!-- no translation found for transcode_enable_all (2411165920039166710) -->
- <skip />
- <!-- no translation found for transcode_default (3784803084573509491) -->
- <skip />
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Transcodierung für Apps aktivieren"</string>
+ <string name="transcode_user_control" msgid="6176368544817731314">"Standardeinstellungen für Transcodierung überschreiben"</string>
+ <string name="transcode_enable_all" msgid="2411165920039166710">"Transcodierung aktivieren"</string>
+ <string name="transcode_default" msgid="3784803084573509491">"Voraussetzen, dass Apps moderne Formate unterstützen"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Aktive Dienste"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Momentan ausgeführte Dienste anzeigen und steuern"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-Implementierung"</string>
@@ -569,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kabelgebundene Kopfhörer"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"An"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Aus"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Mobilfunknetzwerk wird gewechselt"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobile Daten deaktiviert"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Nicht für Datennutzung konfiguriert"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Kein Telefon"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefonsignal - ein Balken"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefonsignal - zwei Balken"</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefonsignal - drei Balken"</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Volle Telefonsignalstärke"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Keine Daten"</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Datensignal - ein Balken"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Datensignal - zwei Balken"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Datensignal - drei Balken"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Volle Datensignalstärke"</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet nicht verbunden"</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet verbunden"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 3affbce..66244eb 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Παράκαμψη προεπιλογών διακωδικοποίησης"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Ενεργοποίηση διακωδικοποίησης"</string>
<string name="transcode_default" msgid="3784803084573509491">"Να θεωρείται ότι οι εφαρμογές χρησιμοποιούν σύγχρονες μορφές"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Ενεργοποίηση διακωδικοποίησης για εφαρμογές"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Υπηρεσίες που εκτελούνται"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Προβολή και έλεγχος των εφαρμογών που εκτελούνται αυτή τη στιγμή"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Υλοποίηση WebView"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Ενσύρματα ακουστικά"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ενεργό"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Ανενεργό"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Αλλαγή δικτύου εταιρείας κινητής τηλεφωνίας"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Τα δεδομένα κινητής τηλεφωνίας απενεργοποιήθηκαν"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Δεν ρυθμίστηκε ώστε να χρησιμοποιεί δεδομένα"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Δεν υπάρχει τηλέφωνο."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Μία γραμμή τηλεφώνου."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Δύο γραμμές τηλεφώνου."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Τρεις γραμμές μπαταρίας."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Πλήρες σήμα τηλεφώνου."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Δεν υπάρχουν δεδομένα."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Μία γραμμή δεδομένων."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Δύο γραμμές δεδομένων."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Τρεις γραμμές δεδομένων."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Πλήρες σήμα δεδομένων."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Το Ethernet αποσυνδέθηκε."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Το Ethernet συνδέθηκε."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 9d5debb..f5a0e2c 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Override transcoding defaults"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Enable transcoding"</string>
<string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Enable transcoding for apps"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator network changing"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobile data off"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Not set to use data"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"No phone."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Phone one bar."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Phone two bars."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Phone three bars."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Phone signal full."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"No data."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data one bar."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data two bars."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data three bars."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Data signal full."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet disconnected."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet connected."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index b0190a2..6f11e80 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Override transcoding defaults"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Enable transcoding"</string>
<string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Enable transcoding for apps"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator network changing"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobile data off"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Not set to use data"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"No phone."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Phone one bar."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Phone two bars."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Phone three bars."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Phone signal full."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"No data."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data one bar."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data two bars."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data three bars."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Data signal full."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet disconnected."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet connected."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 9d5debb..f5a0e2c 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Override transcoding defaults"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Enable transcoding"</string>
<string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Enable transcoding for apps"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator network changing"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobile data off"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Not set to use data"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"No phone."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Phone one bar."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Phone two bars."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Phone three bars."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Phone signal full."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"No data."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data one bar."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data two bars."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data three bars."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Data signal full."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet disconnected."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet connected."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 9d5debb..f5a0e2c 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Override transcoding defaults"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Enable transcoding"</string>
<string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Enable transcoding for apps"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator network changing"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobile data off"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Not set to use data"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"No phone."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Phone one bar."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Phone two bars."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Phone three bars."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Phone signal full."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"No data."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data one bar."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data two bars."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data three bars."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Data signal full."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet disconnected."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet connected."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 9296a59..bfca1095 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Override transcoding defaults"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Enable transcoding"</string>
<string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Enable transcoding for apps"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphone"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Carrier network changing"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobile data off"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Not set to use data"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"No phone."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Phone one bar."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Phone two bars."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Phone three bars."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Phone signal full."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"No data."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data one bar."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data two bars."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data three bars."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Data signal full."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet disconnected."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet connected."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 41466be..44ae8c2 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Anular los valores predeterminados de transcodificación"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Habilitar la transcodificación"</string>
<string name="transcode_default" msgid="3784803084573509491">"Suponer que las apps admiten formatos modernos"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Habilitar transcodificación en apps"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"En ejecución"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Ver y controlar servicios actuales en ejecución"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementación de WebView"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculares con cable"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activar"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivar"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Cambio de proveedor de red"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Datos móviles desactivados"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"No se configuró para usar datos"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Sin teléfono"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Una barra de teléfono"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Dos barras de teléfono"</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Tres barras de teléfono"</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Señal de teléfono completa"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"No hay datos."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Una barra de datos"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Dos barras de datos"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Tres barras de datos"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Señal de datos completa"</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet desconectada"</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet conectada"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 8a0a123..236394c 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Anular valores predeterminados de transcodificación"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Habilitar transcodificación"</string>
<string name="transcode_default" msgid="3784803084573509491">"Considerar que las aplicaciones admiten formatos modernos"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Habilitar transcodificación en las aplicaciones"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Servicios en ejecución"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Ver y controlar los servicios en ejecución"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementación de WebView"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculares con cable"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activado"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivado"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Cambiando la red del operador"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Datos desactiv."</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"No está establecido para usar los datos"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Sin teléfono"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Una barra de cobertura"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Dos barras de cobertura"</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Tres barras de cobertura"</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Cobertura al máximo"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Sin datos"</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Una barra de datos"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Dos barras de datos"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Tres barras de datos"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Señal de datos al máximo"</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Conexión Ethernet desconectada."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Conexión Ethernet conectada."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 4b82c08..c8fd94f 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Alista transkodeerimise vaikeseaded"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Luba transkodeerimine"</string>
<string name="transcode_default" msgid="3784803084573509491">"Oleta, et rakendused toetavad kaasaegseid vorminguid"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Luba rakenduste puhul transkodeerimine"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Käitatud teenused"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Praegu käitatud teenuste vaatamine ja juhtimine"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView\' rakendamine"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Juhtmega kõrvaklapid"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Sees"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Väljas"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operaatori võrku muudetakse"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobiilne andmeside on väljas"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Ei ole andmeside kasutamiseks seadistatud"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Telefonisignaal puudub"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefonisignaal: üks pulk."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefonisignaal: kaks pulka."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefonisignaal: kolm pulka."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefonisignaal on tugev."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Andmed puuduvad."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Andmesignaal: üks pulk."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Andmeside: kaks pulka."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Andmeside: kolm pulka."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Andmesignaal on tugev."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Etherneti-ühendus on katkestatud."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Etherneti-ühendus on loodud."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 37c1fd8..226ffba 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Ez erabili transkodetzearen balio lehenetsiak"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Gaitu transkodetzea"</string>
<string name="transcode_default" msgid="3784803084573509491">"Arduratu aplikazioek formatu modernoak onartzeaz"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Gaitu aplikazioak transkodetzeko aukera"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Abian diren zerbitzuak"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Ikusi eta kontrolatu une honetan abian diren zerbitzuak"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView inplementazioa"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Entzungailu kableduna"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktibatu"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desaktibatu"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operadorearen sarea aldatzen"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Desaktibatuta dago datu-konexioa"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Ez dago ezarrita datuak erabiltzeko"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Ez dago telefono-zenbakirik."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefono-seinaleak barra bat du."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefono-seinaleak bi barra ditu."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefono-seinaleak hiru barra ditu."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefono-seinale osoa."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Ez dago daturik."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Datu-seinaleak barra bat du."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Datu-seinaleak bi barra ditu."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Datu-seinaleak hiru barra ditu."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Datu-seinale osoa."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet bidezko konexioa eten da."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet bidez konektatu da."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 7d20aaf..917a637 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ملغی کردن پیشفرضهای تراتبدیل"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"فعال کردن تراتبدیل"</string>
<string name="transcode_default" msgid="3784803084573509491">"فرض شود برنامهها از قالبهای مدرن پشتیبانی میکنند"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"فعال کردن تراتبدیل برای برنامهها"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"سرویسهای در حال اجرا"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"مشاهده و کنترل سرویسهای در حال اجرای فعلی"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"اجرای وبنما"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"هدفون سیمی"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"روشن"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"خاموش"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"تغییر شبکه شرکت مخابراتی"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"داده تلفن همراه خاموش است"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"برای استفاده از داده تنظیم نشده است"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"بدون تلفن."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"یک نوار برای تلفن."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"دو نوار برای تلفن."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"سه نوار برای تلفن."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"قدرت امواج تلفن همراه کامل است."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"دادهای وجود ندارد."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"یک نوار برای داده."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"دو نوار برای داده."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"سه نوار برای داده."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"قدرت سیگنال داده کامل است."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"اترنت قطع شد."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"اترنت متصل شد."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index a43c5d7..6081b2a 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Ohita transkoodauksen oletukset"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Salli transkoodaus"</string>
<string name="transcode_default" msgid="3784803084573509491">"Oleta, että sovellukset tukevat nykyaikaisia formaatteja"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Ota sovellusten transkoodaus käyttöön"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Käynnissä olevat palvelut"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Tarkastele ja hallitse käynnissä olevia palveluita."</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-käyttöönotto"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Langalliset kuulokkeet"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Päällä"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Poissa päältä"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operaattorin verkko muuttuu"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobiilidata poistettu käytöstä"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Ei käytä dataa"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Ei puhelinverkkoyhteyttä."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Puhelinverkkosignaali - yksi palkki."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Puhelinverkkosignaali - kaksi palkkia."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Puhelinverkkosignaali - kolme palkkia."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Vahva puhelinverkkosignaali."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Ei datasignaalia."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Datasignaali - yksi palkki."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Datasignaali - kaksi palkkia."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Datasignaali - kolme palkkia"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Vahva kuuluvuus."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet on irrotettu."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet on yhdistetty."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 0cb7b17..91d14d4 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Remplacer les valeurs par défaut de transcodage"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Activer le transcodage"</string>
<string name="transcode_default" msgid="3784803084573509491">"Présumer que les applications prennent en charge les formats modernes"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Activer le transcodage pour les applications"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Services en cours d\'exécution"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Afficher et contrôler les services en cours d\'exécution"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Mise en œuvre WebView"</string>
@@ -494,7 +493,6 @@
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"Les adresses MAC sont randomisées"</string>
<plurals name="wifi_tether_connected_summary" formatted="false" msgid="6317236306047306139">
<item quantity="one">%1$d appareil connecté</item>
- <item quantity="many">%1$d devices connected</item>
<item quantity="other">%1$d appareils connectés</item>
</plurals>
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Plus longtemps."</string>
@@ -567,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Écouteurs filaires"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activé"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Désactivé"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Changer de réseau de fournisseur de services"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Désactivées"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Non configuré pour l\'utilisation des données cellulaires"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Aucun signal"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Signal : faible"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Signal : moyen"</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Signal : bon"</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Signal excellent"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Aucun signal"</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Signal faible"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Signal moyen"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Signal bon"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Signal excellent"</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet déconnecté."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet connecté."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index e928a48..2518fe1 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -251,7 +251,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certification affichage sans fil"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Autoriser l\'enregistrement d\'infos Wi-Fi détaillées"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Limiter la recherche Wi‑Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Chgt aléatoire d\'adresse MAC en Wi-Fi"</string>
+ <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Changement aléatoire d\'adresse MAC en Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Données mobiles toujours actives"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Accélération matérielle pour le partage de connexion"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Afficher les appareils Bluetooth sans nom"</string>
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Ignorer les paramètres de transcodage par défaut"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Activer le transcodage"</string>
<string name="transcode_default" msgid="3784803084573509491">"Supposer que les applications sont compatibles avec les formats modernes"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Activer le transcodage pour les applications"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Services en cours d\'exécution"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Afficher et contrôler les services en cours d\'exécution"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Mise en œuvre WebView"</string>
@@ -494,7 +493,6 @@
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"La sélection des adresses MAC est aléatoire"</string>
<plurals name="wifi_tether_connected_summary" formatted="false" msgid="6317236306047306139">
<item quantity="one">%1$d appareil connecté</item>
- <item quantity="many">%1$d devices connected</item>
<item quantity="other">%1$d appareils connectés</item>
</plurals>
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Plus longtemps."</string>
@@ -567,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Casque filaire"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Allumé"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Éteint"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Modification du réseau de l\'opérateur"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Désactivées"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Non configuré pour utiliser les données"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Aucun signal"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Signal : faible"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Signal : moyen"</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Signal : bon"</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Signal excellent"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Aucun signal"</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Signal faible"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Signal moyen"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Signal bon"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Signal excellent"</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet déconnecté"</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet connecté"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index c439253..486afe3 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Anular valores predeterminados de transcodificación"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Activar transcodificación"</string>
<string name="transcode_default" msgid="3784803084573509491">"Considerar que as aplicacións admiten formatos modernos"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Activar transcodificación para as aplicacións"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Servizos en uso"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Comproba e controla os servizos actualmente en uso"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementación de WebView"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculares con cable"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activar"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivar"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Cambio de rede do operador"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Os datos móbiles están desactivados"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Non se configurou para utilizar datos"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Sen teléfono"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Unha barra de cobertura"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Dúas barras de cobertura"</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Tres barras de cobertura"</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Cobertura ao máximo"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Sen datos"</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Unha barra de sinal de datos"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Sinal de datos: dúas barras"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Tres barras de sinal de datos"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Sinal de datos: completo"</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Desconectouse a Ethernet."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Conectouse a Ethernet."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 7dfdcee..2bebe36 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -400,13 +400,9 @@
<string name="inactive_app_active_summary" msgid="8047630990208722344">"સક્રિય. ટોગલ કરવા માટે ટૅપ કરો."</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"ઍપ સ્ટૅન્ડબાયની સ્થિતિ:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
<string name="transcode_settings_title" msgid="2581975870429850549">"મીડિયાનું ફૉર્મેટ બદલવાની પ્રક્રિયાના સેટિંગ"</string>
- <!-- no translation found for transcode_user_control (6176368544817731314) -->
- <skip />
- <!-- no translation found for transcode_enable_all (2411165920039166710) -->
- <skip />
- <!-- no translation found for transcode_default (3784803084573509491) -->
- <skip />
- <string name="transcode_skip_apps" msgid="8249721984597390142">"ઍપ માટે ફૉર્મેટ બદલવાની પ્રક્રિયા ચાલુ કરો"</string>
+ <string name="transcode_user_control" msgid="6176368544817731314">"ફૉર્મેટ બદલવાની પ્રક્રિયાના ડિફૉલ્ટ સેટિંગ ઓવરરાઇડ કરો"</string>
+ <string name="transcode_enable_all" msgid="2411165920039166710">"ફૉર્મેટ બદલવાની પ્રક્રિયા ચાલુ કરો"</string>
+ <string name="transcode_default" msgid="3784803084573509491">"ધારો કે ઍપ આધુનિક ફૉર્મેટ પર કામ કરે છે"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"ચાલુ સેવાઓ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"હાલમાં ચાલતી સેવાઓ જુઓ અને નિયંત્રિત કરો"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView અમલીકરણ"</string>
@@ -569,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"વાયરવાળો હૅડફોન"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ચાલુ"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"બંધ"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"કૅરીઅર નેટવર્કમાં ફેરફાર થઈ રહ્યો છે"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"મોબાઇલ ડેટા બંધ છે"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"ડેટાનો ઉપયોગ કરવાનું સેટ કર્યું નથી"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"કોઈ ફોન નથી."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"ફોન એક બાર."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"ફોન બે બાર."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"ફોન ત્રણ બાર."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"પૂર્ણ ફોન સિગ્નલ."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"કોઈ ડેટા નથી."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"ડેટા એક બાર."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"ડેટા બે બાર."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"ડેટા ત્રણ બાર."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"ડેટા સિગ્નલ પૂર્ણ."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ઇથરનેટ ડિસ્કનેક્ટ થયું."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ઇથરનેટ કનેક્ટ થયું."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 26d1a756..824ab25 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -402,8 +402,7 @@
<string name="transcode_settings_title" msgid="2581975870429850549">"मीडिया ट्रांसकोडिंग सेटिंग"</string>
<string name="transcode_user_control" msgid="6176368544817731314">"ट्रांसकोडिंग की डिफ़ॉल्ट सेटिंग बदलें"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"ट्रांसकोडिंग चालू करें"</string>
- <string name="transcode_default" msgid="3784803084573509491">"मानकर चलें कि ऐप्लिकेशन, मॉडर्न फ़ॉर्मैट के साथ काम करेंगे"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"ऐप्लिकेशन के लिए ट्रांसकोडिंग चालू करें"</string>
+ <string name="transcode_default" msgid="3784803084573509491">"मानकर चलें कि ऐप्लिकेशन, नए फ़ॉर्मैट के साथ काम करेंगे"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"चल रही सेवाएं"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"इस समय चल रही सेवाओं को देखें और नियंत्रित करें"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"वेबव्यू लागू करें"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"वायर वाला हेडफ़ोन"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"चालू है"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"बंद है"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"मोबाइल और इंटरनेट सेवा देने वाली कंपनी का नेटवर्क बदल रहा है"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3जी"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"एलटीई"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"मोबाइल डेटा बंद है"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"डेटा इस्तेमाल करने के लिए सेट नहीं किया गया है"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"कोई फ़ोन नहीं."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"फ़ोन एक बार."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"फ़ोन दो बार."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"फोन तीन बार."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"फ़ोन सिग्नल पूरा."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"कोई डेटा नहीं."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"डेटा एक बार."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"डेटा दो बार."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"डेटा तीन बार."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"डेटा सिग्नल पूरा."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ईथरनेट डिस्कनेक्ट किया गया."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ईथरनेट कनेक्ट किया गया."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index eccfd7a..cd21a5f 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Nadjačaj zadane postavke konvertiranja"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Omogući konvertiranje"</string>
<string name="transcode_default" msgid="3784803084573509491">"Pretpostavi da aplikacije podržavaju moderne formate"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Omogućivanje konvertiranja za aplikacije"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Pokrenute usluge"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Pregledajte i kontrolirajte pokrenute usluge"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementacija WebViewa"</string>
@@ -567,4 +566,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žičane slušalice"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Uključeno"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Isključeno"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Promjena mreže mobilnog operatera"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G i više"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobilni su podaci isključeni"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Nije postavljeno za upotrebu podataka"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Nema telefona."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefonski signal jedan stupac."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefonski signal dva stupca."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefonski signal tri stupca."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefonski signal pun."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Nema podataka."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Podatkovni signal jedan stupac."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Podatkovni signal dva stupca."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Podatkovni signal tri stupca."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Podatkovni signal pun."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Prekinuta je veza s ethernetom."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Uspostavljena je veza s ethernetom."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index e5d4bd1..c3b859c 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Az átkódolás alapértelmezett beállításainak felülbírálása"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Átkódolás engedélyezése"</string>
<string name="transcode_default" msgid="3784803084573509491">"Annak feltételezése, hogy az alkalmazások támogatják a modern formátumokat"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Átkódolás engedélyezése az alkalmazásoknál"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Futó szolgáltatások"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"A jelenleg futó szolgáltatások megtekintése és vezérlése"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-megvalósítás"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vezetékes fejhallgató"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Be"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Ki"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Szolgáltatói hálózat váltása"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobiladatok kikapcsolva"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Nincs beállítva az adathasználat"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Nincs telefon."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefon egy sáv."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefon két sáv."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefon három sáv."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefonjel megtelt."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Nincsenek adatok."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Adat egy sáv."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Adat két sáv."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Adat három sáv."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Adatjel teljes."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet leválasztva."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet csatlakoztatva."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 53eb766..041ad0e 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Չեղարկել վերակոդավորման կանխադրված կարգավորումները"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Միացնել վերակոդավորումը"</string>
<string name="transcode_default" msgid="3784803084573509491">"Ենթադրել, որ հավելվածներն աջակցում են ժամանակակից ձևաչափեր"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Միացնել վերակոդավորումը հավելվածների համար"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Աշխատող ծառայություններ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Դիտել և վերահսկել ընթացիկ աշխատող ծառայությունները"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ծառայություն"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Լարով ականջակալ"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Միացնել"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Անջատել"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Օպերատորի ցանցի փոփոխություն"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Բջջային ինտերնետն անջատված է"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Բջջային ինտերնետն ըստ կանխադրման չի օգտագործվում"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Հեռախոս չկա:"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Հեռախոսի մեկ գիծ:"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Հեռախոսի երկու գիծ:"</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Հեռախոսի երեք գիծ:"</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Հեռախոսի ազդանշանը լիքն է:"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Տվյալներ չկան:"</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Տվյալների մեկ գիծ:"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Տվյալների երկու գիծ:"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Տվյալների երեք գիծ:"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Տվյալների ազդանշանը լրիվ է:"</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet-ը անջատված է:"</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet-ը կապակցված է:"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index edce3c5..69d4582 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Ganti default transcoding"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Aktifkan transcoding"</string>
<string name="transcode_default" msgid="3784803084573509491">"Asumsikan aplikasi mendukung format modern"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Mengaktifkan transcoding untuk aplikasi"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Layanan yang sedang berjalan"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Melihat dan mengontrol layanan yang sedang berjalan"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Penerapan WebView"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Headphone berkabel"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktif"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Nonaktif"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Jaringan operator berubah"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Kuota nonaktif"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Tidak disetel untuk menggunakan data"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Tidak dapat melakukan panggilan."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Ponsel satu batang."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Ponsel dua batang."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Ponsel tiga batang."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Sinyal ponsel penuh."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Tidak ada data yang diterima."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data satu batang."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data dua batang."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data tiga batang."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Sinyal data penuh."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet terputus."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet tersambung."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 9e072cc..f401364 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Hnekkja sjálfgefinni umkóðun"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Kveikja á umkóðun"</string>
<string name="transcode_default" msgid="3784803084573509491">"Gera ráð fyrir að forrit styðji nútímasnið"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Kveikja á umkóðun í forritum"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Þjónustur í gangi"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Skoða og stjórna þjónustum í gangi"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Innleiðing WebView"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Heyrnartól með snúru"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Kveikt"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Slökkt"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Skiptir um farsímakerfi"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Slökkt á farsímagögnum"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Ekki stillt á að nota gögn"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Ekkert símasamband."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Styrkur símasambands er eitt strik."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Styrkur símasambands er tvö strik."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Styrkur símasambands er þrjú strik."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Fullur styrkur símasambands."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Engin gögn."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Sendistyrkur gagnatengingar er eitt strik."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Sendistyrkur gagnatengingar tvö strik."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Sendistyrkur gagnatengingar er þrjú strik."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Fullur sendistyrkur gagnatengingar."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet aftengt."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet tengt."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index fc87d89..ef5e2ff 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Sostituisci impostazioni predefinite transcodifica"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Attiva transcodifica"</string>
<string name="transcode_default" msgid="3784803084573509491">"Presupponi che le app supportino i formati moderni"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Attiva transcodifica per le app"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Servizi in esecuzione"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Visualizza e controlla i servizi attualmente in esecuzione"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementazione di WebView"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Cuffie con cavo"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Cambio della rete dell\'operatore"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Dati mobili disattivati"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Non impostato per l\'utilizzo dei dati"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Nessun telefono."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefono: una barra."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefono: due barre."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefono: tre barre."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Massimo segnale telefonico."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Nessun dato."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Dati: una barra."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Dati: due barre."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Dati: tre barre."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Massimo segnale dati."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Connessione Ethernet annullata."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Connessione Ethernet stabilita."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index b899b59..4cc6775 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ביטול ברירות המחדל של המרת קידוד"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"הפעלת המרת קידוד"</string>
<string name="transcode_default" msgid="3784803084573509491">"הנחת העבודה היא שאפליקציות תומכות בפורמטים מודרניים"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"הפעלה של המרת קידוד לאפליקציות"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"שירותים פועלים"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"הצגת השירותים הפועלים כעת ושליטה בהם"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"יישום WebView"</string>
@@ -568,4 +567,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"אוזניות חוטיות"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"פועלת"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"כבויה"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"רשת ספק משתנה"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"+H"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"+4G"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"+LTE"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"חבילת הגלישה כבויה"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"לא מוגדרת לשימוש בנתונים"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"אין טלפון."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"פס אחד של טלפון."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"שני פסים של טלפון."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"שלושה פסים של טלפון."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"אות הטלפון מלא."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"אין נתונים."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"פס אחד של נתונים."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"שני פסים של נתונים."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"שלושה פסים של נתונים."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"אות הנתונים מלא."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"אתרנט מנותק."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"אתרנט מחובר."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index ded207d..9e9db3d 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"デフォルトのコード変換をオーバーライド"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"コード変換を有効にする"</string>
<string name="transcode_default" msgid="3784803084573509491">"アプリによる最新形式のサポートを想定"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"アプリに対しコード変換を有効にする"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"実行中のサービス"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"現在実行中のサービスを表示して制御する"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView の実装"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有線ヘッドフォン"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ON"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"OFF"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"携帯通信会社のネットワークを変更します"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"モバイルデータ OFF"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"データを使用するように設定されていません"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"電波状態:なし"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"電波状態:レベル1"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"電波状態:レベル2"</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"電波状態:レベル3"</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"電波状態:フル"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"データ信号:なし"</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"データ信号:レベル1"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"データ信号:レベル2"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"データ信号:レベル3"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"データ信号:フル"</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"イーサネット接続を解除しました。"</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"イーサネットに接続しました。"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 2d89dc6..ec39008 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ტრანსკოდირების ნაგულისხმევების უგულებელყოფა"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"ტრანსკოდირების ჩართვა"</string>
<string name="transcode_default" msgid="3784803084573509491">"დაშვება, რომ აპებს აქვთ თანამედროვე ფორმატების მხარდაჭერა"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"ტრანსკოდირების ჩართვა აპებისთვის"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"მიმდინარე სერვისები"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ამჟამად მოქმედი სერვისების ნახვა და მართვა"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView რეალიზაცია"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"სადენიანი ყურსასმენი"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ჩართვა"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"გამორთვა"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"ოპერატორის ქსელის შეცვლა"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"მობილური ინტერნეტი გამორთულია"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"არ არის დაყენებული მონაცემების გამოყენებისთვის"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"ტელეფონი არ არის."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"ტელეფონის სიგნალი ერთ ზოლზეა."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"ტელეფონის სიგნალი ორ ზოლზეა."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"ტელეფონის სიგნალი სამ ზოლზეა."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"ტელეფონის სიგნალი სრულია."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"მონაცემები არ არის."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"თარიღი ზოლზე."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"მონაცემების გადაცემა: ორი ზოლი"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"მონაცემების გადაცემა: სამი ზოლი"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"მონაცემთა გადაცემის საიმედო სიგნალი."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet კავშირი შეწყვეტილია."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet დაკავშირებულია."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index fa99529..881a13c 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Қайта қодтаудың әдепкі параметрлерін қайта анықтау"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Қайта кодтауды қосу"</string>
<string name="transcode_default" msgid="3784803084573509491">"Қолданбалар қазіргі заманғы форматтарды қолдайды делік"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Қолданбалар үшін қайта кодтауға рұқсат ету"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Қосылып тұрған қызметтер"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Қазір істеп тұрған қызметтерді көру және басқару"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView қызметі"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Сымды құлақаспап"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Қосу"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Өшіру"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Оператор желісін өзгерту"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Мобильдік деректер өшірулі"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Деректерді пайдалануға реттелмеген."</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Телефон жоқ."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Телефон бір баған."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Телефон екі баған."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Телефон үш баған."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Телефон сигналы толық."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Дерекқор жоқ."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Дерекқор бір баған."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Дерекқор екі баған."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Дерекқор үш баған."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Дерекқор сигналы толы."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet ажыратылған."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet қосылған."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index a2b5e01..14f7788 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"លុបពីលើលំនាំដើមនៃការបំប្លែងកូដ"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"បើកការបំប្លែងកូដ"</string>
<string name="transcode_default" msgid="3784803084573509491">"សន្មតថាកម្មវិធីអាចប្រើទម្រង់ទំនើបបាន"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"បើកការបំប្លែងកូដសម្រាប់កម្មវិធី"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"សេវាកម្មកំពុងដំណើរការ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"មើល និងគ្រប់គ្រងសេវាកម្មកំពុងដំណើរការបច្ចុប្បន្ន"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"ការអនុវត្ត WebView"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"កាសមានខ្សែ"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"បើក"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"បិទ"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"បណ្តាញក្រុមហ៊ុនសេវាទូរសព្ទកំពុងផ្លាស់ប្តូរ"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"ទិន្នន័យទូរសព្ទចល័តបានបិទ"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"មិនបានកំណត់ឱ្យប្រើទិន្នន័យទេ"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"គ្មានទូរស័ព្ទ។"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"សេវាទូរស័ព្ទមួយកាំ។"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"សេវាទូរស័ព្ទពីរកាំ។"</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"សេវាទូរស័ព្ទបីកាំ។"</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"សេវាទូរស័ព្ទពេញ។"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"គ្មានទិន្នន័យ។"</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"ទិន្នន័យមួយកាំ។"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"ទិន្នន័យពីរកាំ។"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"ទិន្នន័យបីកាំ។"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"សញ្ញាទិន្នន័យពេញ។"</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"បានផ្តាច់អ៊ីសឺរណិត។"</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"បានភ្ជាប់អ៊ីសឺរណិត។"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index f37cf8b..a279d22 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -400,13 +400,9 @@
<string name="inactive_app_active_summary" msgid="8047630990208722344">"ಸಕ್ರಿಯ. ಟಾಗಲ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"ಅಪ್ಲಿಕೇಶನ್ ಸ್ಟ್ಯಾಂಡ್ಬೈ ಸ್ಥಿತಿ:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
<string name="transcode_settings_title" msgid="2581975870429850549">"ಮೀಡಿಯಾ ಟ್ರಾನ್ಸ್ಕೋಡಿಂಗ್ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
- <!-- no translation found for transcode_user_control (6176368544817731314) -->
- <skip />
- <!-- no translation found for transcode_enable_all (2411165920039166710) -->
- <skip />
- <!-- no translation found for transcode_default (3784803084573509491) -->
- <skip />
- <string name="transcode_skip_apps" msgid="8249721984597390142">"ಆ್ಯಪ್ಗಳಿಗಾಗಿ ಟ್ರಾನ್ಸ್ಕೋಡಿಂಗ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+ <string name="transcode_user_control" msgid="6176368544817731314">"ಟ್ರಾನ್ಸ್ಕೋಡಿಂಗ್ ಡೀಫಾಲ್ಟ್ಗಳನ್ನು ಅತಿಕ್ರಮಿಸಿ"</string>
+ <string name="transcode_enable_all" msgid="2411165920039166710">"ಟ್ರಾನ್ಸ್ಕೋಡಿಂಗ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+ <string name="transcode_default" msgid="3784803084573509491">"ಆ್ಯಪ್ಗಳು ಆಧುನಿಕ ಫಾರ್ಮ್ಯಾಟ್ಗಳನ್ನು ಬೆಂಬಲಿಸುತ್ತದೆ ಎಂದು ಊಹಿಸಿ"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"ರನ್ ಆಗುತ್ತಿರುವ ಸೇವೆಗಳು"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ಈಗ ರನ್ ಆಗುತ್ತಿರುವ ಸೇವೆಗಳನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ನಿಯಂತ್ರಿಸಿ"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ಹೊಂದಿಸಿ"</string>
@@ -569,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ವೈಯರ್ ಹೊಂದಿರುವ ಹೆಡ್ಫೋನ್"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ಆನ್ ಆಗಿದೆ"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ಆಫ್ ಆಗಿದೆ"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"ವಾಹಕ ನೆಟ್ವರ್ಕ್ ಬದಲಾಯಿಸುವಿಕೆ"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"ಮೊಬೈಲ್ ಡೇಟಾ ಆಫ್"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"ಡೇಟಾ ಬಳಸಲು ಹೊಂದಿಸಲಾಗಿಲ್ಲ"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"ಯಾವುದೇ ಫೋನ್ ಇಲ್ಲ."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"ಪೋನ್ ಒಂದು ಪಟ್ಟಿ."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"ಫೋನ್ ಎರಡು ಪಟ್ಟಿಗಳು."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"ಫೋನ್ ಮೂರು ಪಟ್ಟಿಗಳು."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"ಫೋನ್ ಸಂಕೇತ ಪೂರ್ತಿ ಇದೆ."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"ಯಾವುದೇ ಡೇಟಾ ಇಲ್ಲ."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"ಡೇಟಾ ಒಂದು ಪಟ್ಟಿ."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"ಡೇಟಾ ಎರಡು ಪಟ್ಟಿಗಳು."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"ಡೇಟಾ ಮೂರು ಪಟ್ಟಿಗಳು."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"ಡೇಟಾ ಸಂಕೇತ ತುಂಬಿದೆ."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ಇಥರ್ನೆಟ್ ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗಿದೆ."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ಇಥರ್ನೆಟ್ ಸಂಪರ್ಕಗೊಳಿಸಲಾಗಿದೆ."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 73921c2..de69488 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"트랜스코딩 기본값 재정의"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"트랜스코딩 사용"</string>
<string name="transcode_default" msgid="3784803084573509491">"앱이 최신 형식을 지원하는 것으로 가정"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"앱 트랜스코딩 사용 설정"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"실행 중인 서비스"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"현재 실행 중인 서비스 보기 및 제어"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 구현"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"유선 헤드폰"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"사용"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"사용 안 함"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"이동통신사 네트워크 변경"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G 이상"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"모바일 데이터 꺼짐"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"데이터를 사용하도록 설정되지 않음"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"휴대전화의 신호가 없습니다."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"휴대전화 신호 막대가 하나입니다."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"휴대전화 신호 막대가 두 개입니다."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"휴대전화 신호 막대가 세 개입니다."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"휴대전화의 신호가 강합니다."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"데이터가 없습니다."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"데이터 신호 막대가 하나입니다."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"데이터 신호 막대가 두 개입니다."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"데이터 신호 막대가 세 개입니다."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"데이터 신호가 강합니다."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"이더넷에서 연결 해제되었습니다."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"이더넷에 연결되었습니다."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 5e978ba..e70460f 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Демейки жүргүзүлгөн транскоддоону өзгөртүп коюу"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Транскоддоо жүргүзүүнү иштетүү"</string>
<string name="transcode_default" msgid="3784803084573509491">"Колдонмолордо заманбап форматтар колдоого алынат"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Колдонмолорду транскоддоону күйгүзүү"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Иштеп жаткан кызматтар"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Учурда иштеп жаткан кызматтарды көрүп, көзөмөлдөп турасыз"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView кызматы"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Зымдуу гарнитура"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Күйгүзүү"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Өчүрүү"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Байланыш оператору өзгөртүлүүдө"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Мобилдик Интернет өчүрүлгөн"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Дайындарды колдонуу үчүн жөндөлгөн эмес"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Телефон сигналы жок."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Телефон сигналы бир таякча."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Телефон сигналы эки таякча."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Телефон сигналы үч таякча."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Телефон сигналы толук."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Сигнал жок."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Мобилдик интернеттин сигналы бир таякча."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Мобилдик интернеттин сигналы эки таякча."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Мобилдик интернеттин сигналы үч таякча."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Мобилдик интернеттин сигналы толук."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet ажырады."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet туташты."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 498cb25..c63cec8 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ຍົກເລີກຄ່າເລີ່ມຕົ້ນການປ່ຽນຮູບແບບລະຫັດ"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"ເປີດການນຳໃຊ້ການປ່ຽນຮູບແບບລະຫັດ"</string>
<string name="transcode_default" msgid="3784803084573509491">"ສົມມຸດວ່າແອັບຮອງຮັບຮູບແບບສະໄໝໃໝ່"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"ເປີດການນຳໃຊ້ການປ່ຽນຮູບແບບລະຫັດສຳລັບແອັບ"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"ບໍລິການທີ່ເຮັດວຽກຢູ່"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ເບິ່ງ ແລະຈັດການບໍລິການທີ່ກຳລັງເຮັດວຽກຢູ່ໃນປັດຈຸບັນ"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"ການຈັດຕັ້ງປະຕິບັດ WebView"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ຫູຟັງແບບມີສາຍ"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ເປີດ"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ປິດ"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"ການປ່ຽນເຄືອຂ່າຍຜູ້ໃຫ້ບໍລິການ"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"ປິດອິນເຕີເນັດມືຖືແລ້ວ"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"ບໍ່ໄດ້ຕັ້ງໃຫ້ໃຊ້ອິນເຕີເນັດ"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"ບໍ່ມີໂທລະສັບ."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"ສັນຍານນຶ່ງຂີດ."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"ສັນຍານສອງຂີດ."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"ສັນຍານສາມຂີດ."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"ສັນຍານເຕັມ."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"ບໍ່ມີຂໍ້ມູນ."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"ຂໍ້ມູນນຶ່ງຂີດ."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"ຂໍ້ມູນສອງຂີດ."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"ຂໍ້ມູນສາມຂີດ."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"ສັນຍານຂໍ້ມູນເຕັມ."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ອີເທີເນັດຕັດເຊື່ອມຕໍ່ແລ້ວ."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ອີເທີເນັດເຊື່ອມຕໍ່ແລ້ວ."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index c077268..d040edf 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Perkodavimo numatytųjų nustatymų nepaisymas"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Perkodavimo įgalinimas"</string>
<string name="transcode_default" msgid="3784803084573509491">"Manoma, kad programos palaiko modernius formatus"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Įjungti programų perkodavimą"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Vykdomos paslaugos"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Žiūrėti ir valdyti dabar vykdomas paslaugas"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"„WebView“ diegimas"</string>
@@ -568,4 +567,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Laidinės ausinės"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Įjungta"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Išjungta"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Keičiamas operatoriaus tinklas"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobiliojo ryšio duomenys išjungti"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Nenustatyta naudoti duomenis"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Nėra telefono."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Viena telefono juosta."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Dvi telefono juostos."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Trys telefono juostos."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefono signalas stiprus."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Duomenų nėra."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Viena duomenų juosta."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Dvi duomenų juostos."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Trys duomenų juostos."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Stiprus duomenų signalas."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Atsijungta nuo eterneto."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Prijungta prie eterneto."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index d5755511..74c0dd5 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Ignorēt pārkodēšanas noklusējuma iestatījumus"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Iespējot pārkodēšanu"</string>
<string name="transcode_default" msgid="3784803084573509491">"Pieņemt, ka lietotnēs tiek atbalstīti moderni formāti"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Iespējot pārkodēšanu noteiktām lietotnēm"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Aktīvie pakalpojumi"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Pašreiz darbojošos pakalpojumu skatīšana un vadība"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ieviešana"</string>
@@ -567,4 +566,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vadu austiņas"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ieslēgts"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Izslēgts"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Mobilo sakaru operatora tīkla mainīšana"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobilie dati izslēgti"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Nav iestatīts datu lietošanai"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Nav tālruņa."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Tālrunis: viena josla."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Tālrunis: divas joslas."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Tālrunis: trīs joslas."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Pilna piekļuve tālruņa signālam"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Nav datu."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Dati: viena josla"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Dati: divas joslas."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Dati: trīs joslas."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Pilna piekļuve datu signālam."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Pārtraukts savienojums ar tīklu Ethernet."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Izveidots savienojums ar tīklu Ethernet."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 21dcb02..739bceb 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Отфрли стандардни вредности за транскодирање"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Овозможи транскодирање"</string>
<string name="transcode_default" msgid="3784803084573509491">"Претпостави дека апликациите поддржуваат модерни формати"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Овозможете транскодирање за апликациите"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Активни услуги"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Погледнете и контролирајте услуги што се моментално активни"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Воведување WebView"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Жичени слушалки"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Вклучено"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Исклучено"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Променување на мрежата на операторот"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Мобилниот интернет е исклучен"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Не е поставен да користи интернет"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Нема сигнал."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Телефон една цртичка.."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Телефон две цртички."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Телефон три цртички."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Сигналот за телефон е исполнет."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Нема податоци."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Податоци една цртичка."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Сигналот за податоци е на две цртички."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Податоци три цртички."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Сигналот за податоци е исполнет."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Етернетот е исклучен."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Етернетот е поврзан."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 97c22d5..122b481 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -400,13 +400,9 @@
<string name="inactive_app_active_summary" msgid="8047630990208722344">"സജീവം. മാറ്റുന്നതിന് ടാപ്പുചെയ്യുക."</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"ആപ്പ് സ്റ്റാൻഡ്ബൈ നില:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
<string name="transcode_settings_title" msgid="2581975870429850549">"മീഡിയ ട്രാൻസ്കോഡ് ചെയ്യൽ ക്രമീകരണം"</string>
- <!-- no translation found for transcode_user_control (6176368544817731314) -->
- <skip />
- <!-- no translation found for transcode_enable_all (2411165920039166710) -->
- <skip />
- <!-- no translation found for transcode_default (3784803084573509491) -->
- <skip />
- <string name="transcode_skip_apps" msgid="8249721984597390142">"ആപ്പുകൾക്കായി ട്രാൻസ്കോഡ് ചെയ്യുന്നത് പ്രവർത്തനക്ഷമമാക്കുക"</string>
+ <string name="transcode_user_control" msgid="6176368544817731314">"ട്രാൻസ്കോഡ് ചെയ്യൽ ഡിഫോൾട്ടുകൾ അസാധുവാക്കുക"</string>
+ <string name="transcode_enable_all" msgid="2411165920039166710">"ട്രാൻസ്കോഡ് ചെയ്യൽ പ്രവർത്തനക്ഷമമാക്കുക"</string>
+ <string name="transcode_default" msgid="3784803084573509491">"ആപ്പുകൾ ആധുനിക ഫോർമാറ്റുകളെ പിന്തുണയ്ക്കുമെന്ന് കരുതുക"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"പ്രവർത്തിക്കുന്ന സേവനങ്ങൾ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"നിലവിൽ പ്രവർത്തിക്കുന്ന സേവനങ്ങൾ കാണുക, നിയന്ത്രിക്കുക"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView നടപ്പാക്കൽ"</string>
@@ -569,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"വയേർഡ് ഹെഡ്ഫോൺ"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ഓണാണ്"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ഓഫാണ്"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"കാരിയർ നെറ്റ്വർക്ക് മാറ്റൽ"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDG"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"മൊബൈൽ ഡാറ്റ ഓഫാണ്"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"ഡാറ്റ ഉപയോഗിക്കുന്നതിന് സജ്ജീകരിച്ചിട്ടില്ല"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"ഫോൺ സിഗ്നൽ ഒന്നുമില്ല."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"ഫോണിൽ ഒരു ബാർ."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"ഫോണിൽ രണ്ട് ബാർ."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"ഫോണിൽ മൂന്ന് ബാർ."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"ഫോൺ സിഗ്നൽ പൂർണ്ണമാണ്."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"ഡാറ്റാ സിഗ്നൽ ഒന്നുമില്ല."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"ഡാറ്റ ഒരു ബാർ."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"ഡാറ്റ രണ്ട് ബാറുകൾ."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"ഡാറ്റ മൂന്ന് ബാർ."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"ഡാറ്റ സിഗ്നൽ പൂർണ്ണമാണ്."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ഇതർനെറ്റ് വിച്ഛേദിച്ചു."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ഇതർനെറ്റ് കണക്റ്റുചെയ്തു."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 8d1cc33..c7a2edd 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Хөрвүүлгийн өгөгдмөлийг дарах"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Хөрвүүлгийг идэвхжүүлэх"</string>
<string name="transcode_default" msgid="3784803084573509491">"Аппыг орчин үеийн форматыг дэмждэг гэж үздэг"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Аппуудад хөрвүүлгийг идэвхжүүлэх"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Ажиллаж байгаа үйлчилгээнүүд"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Одоо ажиллаж байгаа үйлчилгээнүүдийг харах болон хянах"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView хэрэгжилт"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Утастай чихэвч"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Асаах"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Унтраах"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Оператор компанийн сүлжээг өөрчилж байна"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Мобайл дата унтраалттай байна"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Дата ашиглахаар тохируулаагүй"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Утас байхгүй."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Утас нэг баганатай."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Утас хоёр баганатай."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Утас гурван баганатай."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Утасны дохио дүүрэн."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Дата байхгүй."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Дата нэг баганатай."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Дата хоёр баганатай."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Дата гурван баганатай."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Дата дохио дүүрэн."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet саллаа."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet холбогдсон."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index c20888e..d29cb59 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -400,13 +400,9 @@
<string name="inactive_app_active_summary" msgid="8047630990208722344">"सक्रिय. टॉगल करण्यासाठी टॅप करा."</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"अॅप स्टँडबाय स्थिती: <xliff:g id="BUCKET"> %s</xliff:g>"</string>
<string name="transcode_settings_title" msgid="2581975870429850549">"मीडिया ट्रान्सकोडिंगची सेटिंग्ज"</string>
- <!-- no translation found for transcode_user_control (6176368544817731314) -->
- <skip />
- <!-- no translation found for transcode_enable_all (2411165920039166710) -->
- <skip />
- <!-- no translation found for transcode_default (3784803084573509491) -->
- <skip />
- <string name="transcode_skip_apps" msgid="8249721984597390142">"ॲप्ससाठी ट्रान्सकोडिंग सुरू करा"</string>
+ <string name="transcode_user_control" msgid="6176368544817731314">"ट्रान्सकोडिंग डीफॉल्ट ओव्हरराइड करा"</string>
+ <string name="transcode_enable_all" msgid="2411165920039166710">"ट्रान्सकोडिंग सुरू करा"</string>
+ <string name="transcode_default" msgid="3784803084573509491">"असे गृहीत धरा की, ॲप्स आधुनिक फॉरमॅटना सपोर्ट करतात"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"सुरू सेवा"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"सध्या सुरू असलेल्या सेवा पहा आणि नियंत्रित करा"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"वेबदृश्य अंमलबजावणी"</string>
@@ -569,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"वायर असलेला हेडफोन"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"सुरू करा"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"बंद करा"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"वाहक नेटवर्क बदलत आहे"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"३G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"१X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"४G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"४G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"मोबाइल डेटा बंद आहे"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"डेटा वापरण्यासाठी सेट केलेले नाही"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"कोणताही फोन नाही."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"फोन एक बार."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"फोन दोन बार."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"फोन तीन बार."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"फोन सिग्नल पूर्ण."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"कोणताही डेटा नाही."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"डेटा एक बार."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"डेटा दोन बार."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"डेटा तीन बार."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"डेटा सिग्नल पूर्ण."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"इथरनेट डिस्कनेक्ट केले."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"इथरनेट कनेक्ट केले."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 76840a5..c593e4b 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Batalkan transpengekodan lalai"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Dayakan transpengekodan"</string>
<string name="transcode_default" msgid="3784803084573509491">"Mengambil alih sokongan apl format moden"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Dayakan transpengekodan untuk apl"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Perkhidmatan dijalankan"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Lihat dan kawal perkhidmatan yang sedang dijalankan"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Pelaksanaan WebView"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Fon kepala berwayar"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Hidup"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Mati"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Rangkaian pembawa berubah"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Data mudah alih dimatikan"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Tidak ditetapkan untuk menggunakan data"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Tiada telefon."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefon satu bar."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefon dua bar."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefon tiga bar."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Isyarat telefon penuh."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Tiada data."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data satu bar."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data dua bar."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data tiga bar."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Isyarat data penuh."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet diputuskan sambungan."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet disambungkan."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 377e49da..aa9d3d6 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"အမျိုးအစားပြောင်းခြင်း၏ မူရင်းဆက်တင်များကို အစားထိုးရန်"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"အမျိုးအစားပြောင်းခြင်းကို ဖွင့်ရန်"</string>
<string name="transcode_default" msgid="3784803084573509491">"ဤအက်ပ်များက ဖော်မက်အသစ်များကို ပံ့ပိုးသည်"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"အက်ပ်များအတွက် အမျိုးအစားပြောင်းခြင်းကို ဖွင့်ရန်"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"အလုပ်လုပ်နေသောဝန်ဆောင်မှုများ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"လက်ရှိ ဝန်ဆောင်မှုများကို ကြည့်ရှု ထိန်းသိမ်းသည်"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView အကောင်အထည်ဖော်မှု"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ကြိုးတပ်နားကြပ်"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ဖွင့်ထားသည်"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ပိတ်ထားသည်"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"ဝန်ဆောင်မှုပေးသူ ကွန်ရက် ပြောင်းလဲနေသည်။"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"မိုဘိုင်းဒေတာ ပိတ်ထားသည်"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"ဒေတာအသုံးပြုရန် သတ်မှတ်မထားပါ"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"ဖုန်းလိုင်းမရှိပါ။"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"ဖုန်းလိုင်းတစ်ဘား။"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"ဖုန်းလိုင်းနှစ်ဘား။"</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"ဖုန်းလိုင်းသုံးဘား။"</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"ဖုန်းလိုင်းအပြည့်။"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"ဒေတာမရှိပါ။"</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"ဒေတာတစ်ဘား။"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"ဒေတာထုတ်လွှင့်မှု ၂ဘားဖမ်းမိခြင်း။"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"ဒေတာသုံးဘား။"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"ဒေတာထုတ်လွှင့်မှုအပြည့်ဖမ်းမိခြင်း"</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet နှင့်ချိတ်ဆက်မှုပြတ်တောက်"</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet ချိတ်ဆက်ထား။"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index db93121..9494c39 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Overstyr omkodingsstandarder"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Slå på omkoding"</string>
<string name="transcode_default" msgid="3784803084573509491">"Anta at apper støtter moderne formater"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Aktiver omkoding for apper"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Aktive tjenester"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Se og kontrollér tjenester som kjører"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Hodetelefoner med kabel"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"På"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Av"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Bytting av operatørnettverk"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobildata er slått av"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Ikke konfigurert til å bruke data"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Ingen telefon."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefon – én stolpe."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefon – to stolper."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefon – tre stolper."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefonsignal er fullt."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Ingen data."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data – én stolpe"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data – to stolper."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data – tre stolper."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Datasignal er fullt."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet er frakoblet."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet er tilkoblet."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 25a2919..e31fb4e 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -400,13 +400,9 @@
<string name="inactive_app_active_summary" msgid="8047630990208722344">"सक्रिय। टगल गर्न ट्याप गर्नुहोस्।"</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"एपको स्ट्यान्डबाई अवस्था:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
<string name="transcode_settings_title" msgid="2581975870429850549">"मिडिया ट्रान्सकोडिङ सेटिङ"</string>
- <!-- no translation found for transcode_user_control (6176368544817731314) -->
- <skip />
- <!-- no translation found for transcode_enable_all (2411165920039166710) -->
- <skip />
- <!-- no translation found for transcode_default (3784803084573509491) -->
- <skip />
- <string name="transcode_skip_apps" msgid="8249721984597390142">"एपहरूमा ट्रान्सकोडिङ अन गर्नुहोस्"</string>
+ <string name="transcode_user_control" msgid="6176368544817731314">"ट्रान्सकोडिङसम्बन्धी पूर्वनिर्धारित सेटिङ परिवर्तन गर्नुहोस्"</string>
+ <string name="transcode_enable_all" msgid="2411165920039166710">"ट्रान्सकोडिङ अन गर्नुहोस्"</string>
+ <string name="transcode_default" msgid="3784803084573509491">"एपहरूमा आधुनिक फर्म्याट प्रयोग गर्न मिल्छ भनी मान्नुहोस्"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"चलिरहेका सेवाहरू"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"हाल चालु भइरहेका सेवाहरू हेर्नुहोस् र नियन्त्रण गर्नुहोस्"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView कार्यान्वयन"</string>
@@ -569,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"तारसहितको हेडफोन"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"अन छ"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"अफ छ"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"सेवा प्रदायकको नेटवर्क परिवर्तन गर्ने आइकन"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"मोबाइल डेटा निष्क्रिय छ"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"डेटा प्रयोग गर्ने गरी सेट गरिएन"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"फोन छैन्।"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"फोन एउटा पट्टि।"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"फोन दुई पट्टि।"</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"फोन तिन पट्टिहरू।"</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"फोन सङ्केत भरिएको।"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"डेटा छैन।"</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"डेटाको एउटा पट्टि।"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"डेटा दुई बाधाहरू।"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"डेटा तिन बाधाहरू।"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"डेटा संकेत पूर्ण।"</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"इथरनेट विच्छेद भयो।"</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"इथरनेट जोडियो।"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 0f2cc6f..0b75fdd 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Standaardwaarden voor transcodering overschrijven"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Transcodering inschakelen"</string>
<string name="transcode_default" msgid="3784803084573509491">"Aannemen dat apps moderne indelingen ondersteunen"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Transcodering inschakelen voor apps"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Actieve services"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Services die momenteel actief zijn, weergeven en beheren"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementatie"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Bedrade hoofdtelefoon"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aan"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Uit"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Netwerk van provider wordt gewijzigd"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobiele data uit"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Gebruik van gegevens is niet ingesteld"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Geen telefoonsignaal."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefoon: één streepje."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefoon: twee streepjes."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefoon: drie streepjes."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefoonsignaal is op volle sterkte."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Geen gegevens."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Gegevens: één streepje."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Gegevens: twee streepjes."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Gegevens: drie streepjes."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Gegevenssignaal is op volle sterkte."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernetverbinding verbroken."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet verbonden."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 040dddd..cfde61f 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -400,13 +400,9 @@
<string name="inactive_app_active_summary" msgid="8047630990208722344">"ସକ୍ରିୟ। ବଦଳାଇବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"ଆପ୍ ଷ୍ଟାଣ୍ଡବାଏ ଅବସ୍ଥା:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
<string name="transcode_settings_title" msgid="2581975870429850549">"ମିଡିଆ ଟ୍ରାନ୍ସକୋଡିଂ ସେଟିଂସ୍"</string>
- <!-- no translation found for transcode_user_control (6176368544817731314) -->
- <skip />
- <!-- no translation found for transcode_enable_all (2411165920039166710) -->
- <skip />
- <!-- no translation found for transcode_default (3784803084573509491) -->
- <skip />
- <string name="transcode_skip_apps" msgid="8249721984597390142">"ଆପଗୁଡ଼ିକ ପାଇଁ ଟ୍ରାନ୍ସକୋଡିଂ ସକ୍ଷମ କରନ୍ତୁ"</string>
+ <string name="transcode_user_control" msgid="6176368544817731314">"ଟ୍ରାନ୍ସକୋଡିଂ ଡିଫଲ୍ଟଗୁଡ଼ିକୁ ଓଭରରାଇଡ୍ କରନ୍ତୁ"</string>
+ <string name="transcode_enable_all" msgid="2411165920039166710">"ଟ୍ରାନ୍ସକୋଡିଂକୁ ସକ୍ଷମ କରନ୍ତୁ"</string>
+ <string name="transcode_default" msgid="3784803084573509491">"ଧରିନିଅନ୍ତୁ ଆପଗୁଡ଼ିକ ଆଧୁନିକ ଫର୍ମାଟଗୁଡ଼ିକୁ ସମର୍ଥନ କରେ"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"ଚାଲୁଥିବା ସେବାଗୁଡ଼ିକ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ଏବେ ଚାଲୁଥିବା ସେବାଗୁଡ଼ିକୁ ଦେଖନ୍ତୁ ଓ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"ୱେବ୍ଭ୍ୟୁ ପ୍ରୟୋଗ"</string>
@@ -569,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ତାରଯୁକ୍ତ ହେଡଫୋନ୍"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ଚାଲୁ ଅଛି"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ବନ୍ଦ ଅଛି"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"କେରିଅର୍ ନେଟ୍ୱର୍କ ବଦଳୁଛି"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"ମୋବାଇଲ୍ ଡାଟା ବନ୍ଦ ଅଛି"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"ବ୍ୟବହୃତ ଡାଟା ପାଇଁ ସେଟ୍ ହୋଇନାହିଁ"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"କୌଣସି ଫୋନ୍ ନାହିଁ।"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"ଫୋନର ଗୋଟିଏ ବାର ଅଛି।"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"ଫୋନର ଦୁଇଟି ବାର୍ ଅଛି।"</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"ଫୋନ୍ରେ ତିନୋଟି ବାର୍ ଅଛି।"</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"ଫୋନ୍ ସିଗ୍ନାଲ୍ ପୂର୍ଣ୍ଣ ଅଛି।"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"କୌଣସି ଡାଟା ନାହିଁ।"</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"ଡାଟାର ଗୋଟିଏ ବାର ଅଛି।"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"ଡାଟାର ଦୁଇଟି ବାର୍ ଅଛି।"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"ଡାଟାର ତିନୋଟି ବାର୍ ଅଛି।"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"ଡାଟା ସିଗ୍ନାଲ୍ ପୂର୍ଣ୍ଣ ଅଛି।"</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ଇଥରନେଟ୍ ବିଚ୍ଛିନ୍ନ ହୋଇଛି।"</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ଇଥରନେଟ୍ ସଂଯୁକ୍ତ ହୋଇଛି।"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index e6adff3..1221862 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -400,13 +400,9 @@
<string name="inactive_app_active_summary" msgid="8047630990208722344">"ਕਿਰਿਆਸ਼ੀਲ। ਟੌਗਲ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"ਐਪ ਸਟੈਂਡਬਾਈ ਸਥਿਤੀ:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
<string name="transcode_settings_title" msgid="2581975870429850549">"ਮੀਡੀਆ ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਸੈਟਿੰਗਾਂ"</string>
- <!-- no translation found for transcode_user_control (6176368544817731314) -->
- <skip />
- <!-- no translation found for transcode_enable_all (2411165920039166710) -->
- <skip />
- <!-- no translation found for transcode_default (3784803084573509491) -->
- <skip />
- <string name="transcode_skip_apps" msgid="8249721984597390142">"ਐਪਾਂ ਲਈ ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਚਾਲੂ ਕਰੋ"</string>
+ <string name="transcode_user_control" msgid="6176368544817731314">"ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਦੀਆਂ ਪੂਰਵ-ਨਿਰਧਾਰਤ ਸੈਟਿੰਗਾਂ ਨੂੰ ਓਵਰਰਾਈਡ ਕਰੋ"</string>
+ <string name="transcode_enable_all" msgid="2411165920039166710">"ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਚਾਲੂ ਕਰੋ"</string>
+ <string name="transcode_default" msgid="3784803084573509491">"ਮੰਨ ਲਓ ਕਿ ਐਪਾਂ ਆਧੁਨਿਕ ਫਾਰਮੈਟਾਂ ਦਾ ਸਮਰਥਨ ਕਰਦੀਆਂ ਹਨ"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ਇਸ ਵੇਲੇ ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ ਦੇਖੋ ਅਤੇ ਇਹਨਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ਅਮਲ"</string>
@@ -569,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ਤਾਰ ਵਾਲੇ ਹੈੱਡਫ਼ੋਨ"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ਚਾਲੂ"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ਬੰਦ"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"ਕੈਰੀਅਰ ਨੈੱਟਵਰਕ ਦੀ ਬਦਲੀ"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"ਮੋਬਾਈਲ ਡਾਟਾ ਬੰਦ"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"ਡਾਟਾ ਵਰਤਣ ਲਈ ਸੈੱਟ ਨਹੀਂ"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"ਕੋਈ ਫ਼ੋਨ ਨਹੀਂ।"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"ਫ਼ੋਨ ਇੱਕ ਬਾਰ।"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"ਫ਼ੋਨ ਦੋ ਬਾਰਸ।"</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"ਫ਼ੋਨ ਤਿੰਨ ਬਾਰਸ।"</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"ਫ਼ੋਨ ਸਿਗਨਲ ਪੂਰਾ।"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"ਕੋਈ ਡਾਟਾ ਨਹੀਂ।"</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">" ਡਾਟਾ ਇੱਕ ਬਾਰ।"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">" ਡਾਟਾ ਦੋ ਬਾਰਸ।"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">" ਡਾਟਾ ਤਿੰਨ ਬਾਰ।"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">" ਡਾਟਾ ਸਿਗਨਲ ਪੂਰਾ।"</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ਈਥਰਨੈੱਟ ਡਿਸਕਨੈਕਟ ਹੋ ਗਿਆ।"</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ਈਥਰਨੈੱਟ ਕਨੈਕਟ ਹੋ ਗਿਆ।"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 5690e74..102835c 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -400,13 +400,9 @@
<string name="inactive_app_active_summary" msgid="8047630990208722344">"Aktywna. Dotknij, by zmienić."</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"Stan aplikacji w trybie czuwania: <xliff:g id="BUCKET"> %s</xliff:g>"</string>
<string name="transcode_settings_title" msgid="2581975870429850549">"Ustawienia transkodowania multimediów"</string>
- <!-- no translation found for transcode_user_control (6176368544817731314) -->
- <skip />
- <!-- no translation found for transcode_enable_all (2411165920039166710) -->
- <skip />
- <!-- no translation found for transcode_default (3784803084573509491) -->
- <skip />
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Włącz transkodowanie dla aplikacji"</string>
+ <string name="transcode_user_control" msgid="6176368544817731314">"Zastąp ustawienia domyślne transkodowania"</string>
+ <string name="transcode_enable_all" msgid="2411165920039166710">"Włącz transkodowanie"</string>
+ <string name="transcode_default" msgid="3784803084573509491">"Zakładaj, że aplikacje obsługują nowoczesne formaty"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Uruchomione usługi"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Wyświetl obecnie uruchomione usługi i nimi zarządzaj"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementacja WebView"</string>
@@ -571,4 +567,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Słuchawki przewodowe"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Włączono"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Wyłączono"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Zmiana sieci operatora"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Wyłączona"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Nie skonfigurowano do transmisji danych"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Brak sygnału telefonu."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefon: jeden pasek."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefon: dwa paski."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefon: trzy paski."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefon: pełna moc sygnału."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Brak danych."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Dane: jeden pasek."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Dane: dwa paski."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Dane: trzy paski."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Dane: pełna moc sygnału."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Rozłączono z siecią Ethernet."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Połączono z siecią Ethernet."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index a0ddcf2..99019a6 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Substituir os padrões de transcodificação"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Ativar transcodificação"</string>
<string name="transcode_default" msgid="3784803084573509491">"Considerar que os apps são compatíveis com formatos modernos"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Ativar transcodificação para apps"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Serviços em execução"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Visualizar e controlar os serviços em execução no momento"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementação do WebView"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Fones de ouvido com fio"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ativado"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desativado"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Alteração de rede da operadora"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Dados móveis desativados"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Sem configuração para uso de dados"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Sem telefone."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Uma barra de sinal do telefone."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Duas barras de sinal do telefone."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Três barras de sinal do telefone."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Sinal do telefone cheio."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Nenhum dado."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Uma barra de sinal de dados."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Duas barras de sinal de dados."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Três barras do sinal de dados."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Sinal de dados cheio."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet desconectada."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet conectada."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index adaed74..238e54b 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Substituir as predefinições da transcodificação"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Ativar a transcodificação"</string>
<string name="transcode_default" msgid="3784803084573509491">"Assumir que as apps suportam formatos modernos"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Ative a transcodificação para apps"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Serviços em execução"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Ver e controlar os serviços actualmente em execução"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementação WebView"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auscultadores com fios"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ligado"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desligado"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Rede do operador em mudança."</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Dados móveis desativados"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Não definido para utilizar dados"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Sem telefone."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Uma barra de telefone."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Duas barras de telefone."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Três barras de telefone."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Sinal de telefone completo."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Sem dados."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Uma barra de dados."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Duas barras de dados."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Três barras de dados."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Sinal de dados completo."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet desligada."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet ligada."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index a0ddcf2..99019a6 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Substituir os padrões de transcodificação"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Ativar transcodificação"</string>
<string name="transcode_default" msgid="3784803084573509491">"Considerar que os apps são compatíveis com formatos modernos"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Ativar transcodificação para apps"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Serviços em execução"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Visualizar e controlar os serviços em execução no momento"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementação do WebView"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Fones de ouvido com fio"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ativado"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desativado"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Alteração de rede da operadora"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Dados móveis desativados"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Sem configuração para uso de dados"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Sem telefone."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Uma barra de sinal do telefone."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Duas barras de sinal do telefone."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Três barras de sinal do telefone."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Sinal do telefone cheio."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Nenhum dado."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Uma barra de sinal de dados."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Duas barras de sinal de dados."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Três barras do sinal de dados."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Sinal de dados cheio."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet desconectada."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet conectada."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 266dff2..df95dbc 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Modificați setările prestabilite de transcodare"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Activați transcodarea"</string>
<string name="transcode_default" msgid="3784803084573509491">"Presupuneți că aplicațiile acceptă formatele moderne"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Activați transcodarea pentru aplicații"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Servicii în curs de funcționare"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Vedeți și controlați serviciile care funcționează în prezent"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementare WebView"</string>
@@ -567,4 +566,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Căști cu fir"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activat"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Dezactivat"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Se schimbă rețeaua operatorului"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Date mobile dezactivate"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Nu este setat pentru a folosi datele"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Nu există semnal pentru telefon."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Semnal pentru telefon: o bară."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Semnal pentru telefon: două bare."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Semnal pentru telefon: trei bare."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Semnal pentru telefon: complet."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Nu există semnal pentru date."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Semnal pentru date: o bară."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Semnal pentru date: două bare."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Semnal pentru date: trei bare."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Semnal pentru date: complet."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet deconectat."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet conectat."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index ca20bae..68826d7 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Переопределять настройки транскодирования по умолчанию"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Включить перекодирование"</string>
<string name="transcode_default" msgid="3784803084573509491">"Считать, что приложения поддерживают современные форматы кодирования"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Включить перекодирование для приложений"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Работающие службы"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Просмотр и управление работающими службами"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Сервис WebView"</string>
@@ -568,4 +567,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Проводные наушники"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Вкл."</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Выкл."</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Сменить сеть"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Мобильный Интернет отключен"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Мобильный Интернет по умолчанию не используется."</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Сигнал телефонной сети отсутствует."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Сигнал телефонной сети: одно деление."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Сигнал телефонной сети: два деления."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Сигнал телефонной сети: три деления."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Надежный телефонный сигнал."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Сигнал передачи данных отсутствует."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Сигнал передачи данных: одно деление."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Сигнал передачи данных: два деления."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Сигнал передачи данных: три деления."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Надежный сигнал передачи данных."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Устройство отключено от Ethernet."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Устройство подключено к Ethernet."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index da69b81..736445d 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ට්රාන්ස්කෝඩින් පෙරනිමි ප්රතික්ෂේප කරන්න"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"ට්රාන්ස්කෝඩින් සබල කරන්න"</string>
<string name="transcode_default" msgid="3784803084573509491">"යෙදුම් නවීන ආකෘති සඳහා සහාය දක්වයි යැයි උපකල්පනය කරමු"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"යෙදුම් සඳහා ට්රාන්ස්කෝඩින් සබල කරන්න"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"ධාවනය වන සේවා"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"දැනට ධාවනය වන සේවා බලන්න සහ පාලනය කරන්න"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ක්රියාත්මක කිරීම"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"රැහැන්ගත කළ හෙඩ්ෆෝන්"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ක්රියාත්මකයි"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ක්රියාවිරහිතයි"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"වාහක ජාලය වෙනස් වෙමින්"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"ජංගම දත්ත ක්රියාවිරහිතයි"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"දත්ත භාවිත කිරීමට සකසා නැත"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"දුරකථනයක් නැත."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"දුරකථනය තීරු එකයි."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"දුරකථනය තීරු දෙකයි."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"දුරකථනය තීරු තුනයි."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"දුරකථනයේ සංඥාව පිරී ඇත."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"දත්ත නැත."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"දත්ත තීරු එකයි."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"දත්ත තීරු 2."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"දත්ත තීරු 3."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"දත්ත සංඥාව පිරී ඇත."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ඊතර්නෙට් විසන්ධි කරන ලදී."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ඊතර්නෙට් සම්බන්ධ කරන ලදී."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index b428b42..265ec8f 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Prepísať predvolené nastavenia prekódovania"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Povoliť prekódovanie"</string>
<string name="transcode_default" msgid="3784803084573509491">"Prepdokladať, že aplikácie podporujú moderné formáty"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Zapnúť prekódovanie aplikácií"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Spustené služby"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Zobrazovať a riadiť aktuálne spustené služby"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementácia WebView"</string>
@@ -568,4 +567,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Slúchadlá s káblom"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Zapnúť"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Vypnúť"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Mení sa sieť operátora"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobilné dáta sú vypnuté"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Nie je nastavené na používanie dát"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Žiadna telefónna sieť."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Jeden stĺpec signálu telefónnej siete."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Dve čiarky signálu telefónnej siete."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Tri čiarky signálu telefónnej siete."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Plný signál telefónnej siete."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Žiadna dátová sieť."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Jedna čiarka signálu dátovej siete."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Dve čiarky signálu dátovej siete."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Tri čiarky signálu dátovej siete."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Plný signál dátovej siete."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Sieť ethernet je odpojená"</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Sieť ethernet je pripojená"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 3ba31fa..2e6fc0e 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Preglasi privzete nastavitve prekodiranja"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Omogoči prekodiranje"</string>
<string name="transcode_default" msgid="3784803084573509491">"Aplikacije naj bi podpirale sodobne oblike zapisov"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Omogočanje prekodiranja za aplikacije"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Zagnane storitve"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Preglejte in nadzorujte storitve, ki so trenutno zagnane"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Izvedba spletnega pogleda"</string>
@@ -568,4 +567,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žične slušalke"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Vklop"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Izklop"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Spreminjanje omrežja operaterja"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Prenos podatkov v mobilnem omrežju je izklopljen"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Ni nastavljeno za uporabo prenosa podatkov"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Ni telefona."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefon z eno črtico."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefon z dvema črticama."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefon s tremi črticami."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Signal telefona je poln."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Ni podatkov."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Podatkovni signal z eno črtico."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Podatki z dvema črticama."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Podatki s tremi črticami."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Podatkovni signal poln."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernetna povezava je prekinjena."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernetna povezava je vzpostavljena."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 15cbb74..5774d9b 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -400,13 +400,9 @@
<string name="inactive_app_active_summary" msgid="8047630990208722344">"Aktiv. Trokit për ta ndryshuar."</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"Gjendja e gatishmërisë e aplikacionit:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
<string name="transcode_settings_title" msgid="2581975870429850549">"Cilësimet e transkodimit të multimediave"</string>
- <!-- no translation found for transcode_user_control (6176368544817731314) -->
- <skip />
- <!-- no translation found for transcode_enable_all (2411165920039166710) -->
- <skip />
- <!-- no translation found for transcode_default (3784803084573509491) -->
- <skip />
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Aktivizo transkodimin për aplikacionet"</string>
+ <string name="transcode_user_control" msgid="6176368544817731314">"Anulo parazgjedhjet e transkodimit"</string>
+ <string name="transcode_enable_all" msgid="2411165920039166710">"Aktivizo transkodimin"</string>
+ <string name="transcode_default" msgid="3784803084573509491">"Supozo se aplikacionet i mbështetin formatet moderne"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Shërbimet në ekzekutim"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Shiko dhe kontrollo shërbimet që po ekzekutohen aktualisht"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Zbatimi i WebView"</string>
@@ -569,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kufje me tela"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktive"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Joaktive"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Rrjeti i operatorit celular po ndryshohet"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Të dhënat celulare janë joaktive"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Nuk është caktuar të përdorë të dhënat"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Nuk ka telefon."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefoni ka edhe një vijë."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefoni ka dy vija."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefoni ka tre vija."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Sinjali i telefonit është i plotë."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Nuk ka të dhëna."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Sinjali është vetëm një vijë."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Të dhënat kanë dy vija."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Sinjali është me tre vija."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Sinjali i të dhënave është i plotë."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Lidhja e eternetit u shkëput."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Lidhja e eternetit u lidh."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index c337182..207ca74 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Замени подразумевана подешавања транскодирања"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Омогући транскодирање"</string>
<string name="transcode_default" msgid="3784803084573509491">"Подразумевај да апликације подржавају модерне формате"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Омогућите транскодирање за апликације"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Покренуте услуге"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Приказ и контрола тренутно покренутих услуга"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Примена WebView-а"</string>
@@ -567,4 +566,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Жичане слушалице"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Укључено"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Искључено"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Промена мреже мобилног оператера"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Мобилни подаци су искључени"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Није подешено за коришћење података"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Нема телефона."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Сигнал телефона има једну црту."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Сигнал телефона од две црте."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Сигнал телефона од три црте."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Сигнал телефона је пун."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Нема података."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Сигнал за податке има једну црту."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Сигнал за податке од две црте."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Сигнал за податке од три црте."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Сигнал за податке је најјачи."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Веза са етернетом је прекинута."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Етернет је повезан."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 2bf9785..7afd344 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Åsidosätta standardinställningar för omkodning"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Aktivera omkodning"</string>
<string name="transcode_default" msgid="3784803084573509491">"Anta att appar har stöd för moderna format"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Aktivera omkodning för appar"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Aktiva tjänster"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Visa och styr aktiva tjänster"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Hörlurar med sladd"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"På"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Av"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Byter leverantörsnätverk"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobildata har inaktiverats"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Inte inställd på mobildata"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Ingen telefon."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefon: en stapel."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefon: två staplar."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefon: tre staplar."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefonsignalen är full."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Inga data."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data: en stapel."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data: två staplar."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data: tre staplar."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Datasignalen är full."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet har kopplats från."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet har anslutits."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 610bfee..084b5c93 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Batilisha chaguomsingi za kubadilisha miundo ya faili"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Ruhusu ubadilishaji wa miundo ya faili"</string>
<string name="transcode_default" msgid="3784803084573509491">"Chukulia kuwa programu zinatumia miundo ya kisasa"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Washa ubadilishaji muundo wa faili kwenye programu"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Huduma zinazoendeshwa"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Onyesha na udhibiti huduma zinazoendeshwa kwa sasa"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Utekelezaji wa WebView"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vipokea sauti vya waya"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Umewashwa"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Umezimwa"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Mabadiliko katika mtandao wa mtoa huduma"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Umezima data ya mtandao wa simu"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Haijawekewa mipangilio ya kutumia data"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Hakuna simu"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Mwambaa mmoja wa simu."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Miambaa miwili ya simu"</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Miambaa mitatu ya simu."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Ishara ya simu imejaa."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Hakuna data."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Upapi mmoja wa habari"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Miamba miwili ya data."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Fito tatu za habari."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Ishara ya data imejaa."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethaneti imeondolewa."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethaneti imeunganishwa."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 7d77967..5fdf8bd 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"இயல்புநிலை குறிமாற்றங்களை மீறிச் செயல்படு"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"குறிமாற்றத்தை இயக்கு"</string>
<string name="transcode_default" msgid="3784803084573509491">"ஆப்ஸ் மாடர்ன் வடிவங்களை ஆதரிக்கும்படி அமை"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"ஆப்ஸுக்குக் குறிமாற்றத்தை இயக்கு"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"இயங்கும் சேவைகள்"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"தற்போது இயக்கத்தில் இருக்கும் சேவைகளைப் பார்த்து கட்டுப்படுத்து"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView செயல்படுத்தல்"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"வயருள்ள ஹெட்ஃபோன்"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ஆன்"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ஆஃப்"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"மொபைல் நிறுவன நெட்வொர்க்கை மாற்றும்"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"மொபைல் டேட்டா ஆஃப் செய்யப்பட்டது"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"தரவை உபயோகிக்க அமைக்கப்படவில்லை"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"சிக்னல் இல்லை."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"சிக்னல் ஒரு கோட்டில் உள்ளது."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"சிக்னல் இரண்டு கோட்டில் உள்ளது."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"சிக்னல் மூன்று கோட்டில் உள்ளது."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"சிக்னல் முழுமையாக உள்ளது."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"டேட்டா சிக்னல் இல்லை."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"தரவு சிக்னல் ஒரு கோட்டில் உள்ளது."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"தரவின் சிக்னல் இரண்டு கோடு வரை உள்ளது."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"தரவு சிக்னல் மூன்று கோட்டில் உள்ளது."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"தரவு சிக்னல் முழுமையாக உள்ளது."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ஈத்தர்நெட் துண்டிக்கப்பட்டது."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ஈத்தர்நெட் இணைக்கப்பட்டது."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index f24caec..38f08b2 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -400,13 +400,9 @@
<string name="inactive_app_active_summary" msgid="8047630990208722344">"సక్రియంగా ఉంది. టోగుల్ చేయడానికి నొక్కండి."</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"యాప్ స్టాండ్బై స్థితి:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
<string name="transcode_settings_title" msgid="2581975870429850549">"మీడియా ట్రాన్స్కోడింగ్ సెట్టింగ్లు"</string>
- <!-- no translation found for transcode_user_control (6176368544817731314) -->
- <skip />
- <!-- no translation found for transcode_enable_all (2411165920039166710) -->
- <skip />
- <!-- no translation found for transcode_default (3784803084573509491) -->
- <skip />
- <string name="transcode_skip_apps" msgid="8249721984597390142">"యాప్ల కోసం ట్రాన్స్కోడింగ్ను ఎనేబుల్ చేయండి"</string>
+ <string name="transcode_user_control" msgid="6176368544817731314">"ట్రాన్స్కోడింగ్ ఆటోమేటిక్ సెట్టింగ్లను ఓవర్రైడ్ చేయండి"</string>
+ <string name="transcode_enable_all" msgid="2411165920039166710">"ట్రాన్స్కోడింగ్ను ఎనేబుల్ చేయండి"</string>
+ <string name="transcode_default" msgid="3784803084573509491">"యాప్లు ఆధునిక ఫార్మాట్లకు సపోర్ట్ చేస్తాయని అనుకోండి"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"అమలులో ఉన్న సేవలు"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ప్రస్తుతం అమలులో ఉన్న సేవలను వీక్షించండి మరియు నియంత్రించండి"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"వెబ్ వీక్షణ అమలు"</string>
@@ -569,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"వైర్ ఉన్న హెడ్ఫోన్"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ఆన్లో ఉంది"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ఆఫ్లో ఉంది"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"క్యారియర్ నెట్వర్క్ మారుతోంది"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"మొబైల్ డేటా ఆఫ్లో ఉంది"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"డేటాను ఉపయోగించే విధంగా సెట్ చేయలేదు"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"ఫోన్ లేదు."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"ఫోన్ ఒక బారు."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"ఫోన్ రెండు బార్లు."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"ఫోన్ మూడు బార్లు."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"ఫోన్ సిగ్నల్ పూర్తిగా ఉంది."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"డేటా లేదు."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"డేటా ఒక బారు."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"డేటా రెండు బార్లు."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"డేటా మూడు బార్లు."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"డేటా సిగ్నల్ సంపూర్ణంగా ఉంది."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ఈథర్నెట్ డిస్కనెక్ట్ చేయబడింది."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ఈథర్నెట్ కనెక్ట్ చేయబడింది."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 2c01998..dabb9d3 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ลบล้างค่าเริ่มต้นของการแปลง"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"เปิดใช้การแปลง"</string>
<string name="transcode_default" msgid="3784803084573509491">"ถือว่าแอปรองรับรูปแบบสมัยใหม่"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"เปิดใช้การแปลงสำหรับแอป"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"บริการที่ทำงานอยู่"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ดูและควบคุมบริการที่ทำงานอยู่"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"การใช้งาน WebView"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"หูฟังแบบมีสาย"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"เปิด"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ปิด"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"การเปลี่ยนเครือข่ายผู้ให้บริการ"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"เน็ตมือถือปิดอยู่"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"ไม่ได้ตั้งค่าให้ใช้อินเทอร์เน็ตมือถือ"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"ไม่มีสัญญาณโทรศัพท์"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"สัญญาณโทรศัพท์หนึ่งขีด"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"สัญญาณโทรศัพท์สองขีด"</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"สัญญาณโทรศัพท์สามขีด"</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"สัญญาณโทรศัพท์เต็ม"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"ไม่มีข้อมูล"</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"สัญญาณข้อมูลหนึ่งขีด"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"สัญญาณข้อมูลสองขีด"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"สัญญาณข้อมูลสามขีด"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"สัญญาณข้อมูลเต็ม"</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ยกเลิกการเชื่อมต่ออีเทอร์เน็ตแล้ว"</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"เชื่อมต่ออีเทอร์เน็ตแล้ว"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 54ba90e..b451d89 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"I-override ang mga default ng pagta-transcode"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"I-enable ang pagta-transcode"</string>
<string name="transcode_default" msgid="3784803084573509491">"Ipagpalagay na sinusuportahan ng mga app ang mga modernong format"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"I-enable ang pag-transcode para sa mga app"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Mga tumatakbong serbisyo"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Tingnan at kontrolin ang mga kasalukuyang tumatakbong serbisyo"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Pagpapatupad sa WebView"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired na headphone"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Naka-on"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Naka-off"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Nagpapalit ng carrier network"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Naka-off ang mobile data"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Hindi nakatakdang gumamit ng data"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Walang telepono."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telepono na isang bar."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telepono na dalawang bar."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telepono na tatlong bar."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Puno ang signal ng telepono."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Walang data."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data na isang bar."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data na dalawang bar."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data na tatlong bar."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Puno ang signal ng data."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Nadiskonekta ang Ethernet."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Nakakonekta ang Ethernet."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 942834f..e1ff56b 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Kod dönüştürme varsayılanlarını geçersiz kıl"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Kod dönüştürmeyi etkinleştir"</string>
<string name="transcode_default" msgid="3784803084573509491">"Uygulamaların modern biçimleri desteklediğini varsay"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Uygulamalar için kod dönüştürmeyi etkinleştir"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Çalışan hizmetler"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Şu anda çalışan hizmetleri görüntüle ve denetle"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Web Görünümü kullanımı"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kablolu kulaklık"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Açık"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Kapalı"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operatör ağı değiştiriliyor"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobil veri kapalı"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Veri kullanmak üzere ayarlanmadı"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Telefon sinyali yok."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefon sinyali bir çubuk."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefon sinyali iki çubuk."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefon sinyali üç çubuk."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefon sinyali tam."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Veri yok."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Veri sinyali bir çubuk."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Veri sinyali iki çubuk."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Veri sinyali üç çubuk."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Veri sinyali tam."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet bağlantısı kesildi."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet bağlandı."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index f6063f8..6806ce6 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Замінити стандартні налаштування перекодування"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Увімкнути перекодування"</string>
<string name="transcode_default" msgid="3784803084573509491">"Вважати, що додатки підтримують сучасні формати"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Увімкнути перекодування додатків"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Запущені сервіси"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Переглянути й налаштувати запущені сервіси"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Застосування WebView"</string>
@@ -568,4 +567,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Дротові навушники"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Увімкнено"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Вимкнено"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Змінення мережі оператора"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Мобільне передавання даних вимкнено"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Не вибрано для використання даних"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Немає сигналу телефону."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Одна смужка сигналу телефону."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Дві смужки сигналу телефону."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Три смужки сигналу телефону."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Максимальний сигнал телефону."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Немає сигналу даних."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Одна смужка сигналу даних."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Дві смужки сигналу даних."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Три смужки сигналу даних."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Максимальний сигнал даних."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet відключено."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet підключено."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 5d75437..4363f0b 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -400,13 +400,9 @@
<string name="inactive_app_active_summary" msgid="8047630990208722344">"فعال۔ ٹوگل کرنے کیلئے تھپتھپائیں۔"</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"ایپ اسٹینڈ بائی کی حالت:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
<string name="transcode_settings_title" msgid="2581975870429850549">"میڈیا ٹرانسکوڈنگ کی ترتیبات"</string>
- <!-- no translation found for transcode_user_control (6176368544817731314) -->
- <skip />
- <!-- no translation found for transcode_enable_all (2411165920039166710) -->
- <skip />
- <!-- no translation found for transcode_default (3784803084573509491) -->
- <skip />
- <string name="transcode_skip_apps" msgid="8249721984597390142">"ایپس کے لئے ٹرانسکوڈنگ فعال کریں"</string>
+ <string name="transcode_user_control" msgid="6176368544817731314">"ٹرانسکوڈنگ ڈیفالٹس کو اوور رائیڈ کریں"</string>
+ <string name="transcode_enable_all" msgid="2411165920039166710">"ٹرانسکوڈنگ فعال کریں"</string>
+ <string name="transcode_default" msgid="3784803084573509491">"فرض کریں کہ ایپس جدید فارمیٹس کو سپورٹ کرتی ہیں"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"چل رہی سروسز"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"فی الحال چل رہی سروسز دیکھیں اور انہیں کنٹرول کریں"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView کا نفاذ"</string>
@@ -569,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"وائرڈ ہیڈ فون"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"آن"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"آف"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"کیریئر نیٹ ورک کی تبدیلی"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"موبائل ڈیٹا آف ہے"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"ڈیٹا استعمال کرنے کے لیے سیٹ نہیں ہے"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"کوئی فون نہیں ہے۔"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"فون کا ایک بار۔"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"فون کے دو بارز۔"</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"فون کے تین بارز۔"</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"فون سگنل پورا ہے۔"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"کوئی ڈیٹا نہیں ہے۔"</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"ڈیٹا کا ایک بار۔"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"ڈیٹا کے دو بارز۔"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"ڈیٹا کے تین بارز۔"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"ڈیٹا سگنل بھرا ہوا ہے۔"</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ایتھرنیٹ منقطع ہے۔"</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ایتھرنیٹ منسلک ہے۔"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index f1fc8dd..1eecf88 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -402,8 +402,7 @@
<string name="transcode_settings_title" msgid="2581975870429850549">"Media transkripsiyasi sozlamalari"</string>
<string name="transcode_user_control" msgid="6176368544817731314">"Transkripsiya parametrlarini almashtirish"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Transkripsiyasini yoqish"</string>
- <string name="transcode_default" msgid="3784803084573509491">"Ilovalar zamonaviy kodlash formatlarini qoʻllab-quvvatlaydi deb hisoblash"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Ilovalar uchun transkripsiyani yoqish"</string>
+ <string name="transcode_default" msgid="3784803084573509491">"Ilovalarda zamonaviy kodlash formatlari ishlaydi deb hisoblash"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Ishlab turgan ilovalar"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Ishlab turgan ilovalarni ko‘rish va boshqarish"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ta’minotchisi"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Simli quloqlik"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Yoniq"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Oʻchiq"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Mobil tarmoqni o‘zgartirish"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobil internet yoqilmagan"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Maʼlumotlardan foydalanish uchun sozlanmagan"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Signal yo‘q."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefon bitta panelda."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefon ikkita panelda."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefon uchta panelda."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefon signali to‘liq."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Ma’lumotlar yo‘q."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Ma’lumotlar bitta panelda."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Ma’lumotlar ikkita panelda."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Ma’lumotlar uchta panelda."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Internet signali butun."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Qurilma Ethernet tarmog‘idan uzildi."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Qurilma Ethernet tarmog‘iga ulandi."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 910fa26..643fdb9 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Ghi đè tùy chọn chuyển mã mặc định"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Bật tính năng chuyển mã"</string>
<string name="transcode_default" msgid="3784803084573509491">"Giả định rằng các ứng dụng hỗ trợ định dạng hiện đại"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Bật tùy chọn chuyển mã cho ứng dụng"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Các dịch vụ đang chạy"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Xem và kiểm soát các dịch vụ đang chạy"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Triển khai WebView"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Tai nghe có dây"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Đang bật"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Đang tắt"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Thay đổi mạng của nhà mạng"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Đã tắt dữ liệu di động"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Chưa được đặt để sử dụng dữ liệu"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Không có điện thoại nào."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Tín hiệu điện thoại một vạch."</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Tín hiệu điện thoại hai vạch."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Tín hiệu điện thoại ba vạch."</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Tín hiệu điện thoại đầy đủ."</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Không có dữ liệu."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Tín hiệu dữ liệu một vạch."</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Tín hiệu dữ liệu hai vạch."</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Tín hiệu dữ liệu ba vạch."</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Tín hiệu dữ liệu đầy đủ."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Đã ngắt kết nối Ethernet."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Đã kết nối Ethernet."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index c9ecab1..81d8106 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"覆盖转码默认设置"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"启用转码"</string>
<string name="transcode_default" msgid="3784803084573509491">"假设应用支持现代格式"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"为应用启用转码功能"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"正在运行的服务"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"查看和控制当前正在运行的服务"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 实现"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有线耳机"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"开启"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"关闭"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"运营商网络正在更改"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"移动数据网络已关闭"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"未设置为使用移动数据"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"没有手机信号。"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"手机信号强度为一格。"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"手机信号强度为两格。"</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"手机信号强度为三格。"</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"手机信号满格。"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"没有数据网络信号。"</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"数据信号强度为一格。"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"数据信号强度为两格。"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"数据信号强度为三格。"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"数据信号满格。"</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"以太网已断开连接。"</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"以太网已连接。"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 3bbfa21..39a12aa 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"覆寫轉碼預設設定"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"啟用轉碼功能"</string>
<string name="transcode_default" msgid="3784803084573509491">"假設應用程式支援新型格式"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"為應用程式啟用轉碼功能"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"執行中的服務"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"查看並控制目前正在執行中的服務"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 設置"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有線耳機"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"開啟"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"關閉"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"流動網絡供應商網絡正在變更"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"流動數據已關閉"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"未設定至可使用資料"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"沒有電話訊號。"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"電話訊號強度為一格。"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"電話訊號強度為兩格。"</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"電話訊號強度為三格。"</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"電話訊號滿格。"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"沒有數據網絡。"</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"數據網絡訊號強度為一格。"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"數據網絡訊號強度為兩格。"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"數據網絡訊號強度為三格。"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"數據網絡訊號滿格。"</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"以太網連接中斷。"</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"已連接以太網。"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index b0dbb5f..cc35ed3 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"覆寫轉碼預設設定"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"啟用轉碼"</string>
<string name="transcode_default" msgid="3784803084573509491">"假設應用程式支援新格式"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"替應用程式啟用轉碼功能"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"正在運作的服務"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"查看並管理目前正在執行的服務"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 實作"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有線耳機"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"開啟"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"關閉"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"電信業者網路正在進行變更"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"行動數據已關閉"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"並未設為使用行動數據"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"沒有電話訊號。"</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"電話訊號強度一格。"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"電話訊號強度兩格。"</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"電話訊號強度三格。"</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"電話訊號滿格。"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"沒有數據網路。"</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"數據網路訊號強度一格。"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"數據網路訊號強度兩格。"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"數據網路訊號強度三格。"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"數據網路訊號滿格。"</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"未連上乙太網路。"</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"已連上乙太網路。"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 8f7c2ac1..bcc6369 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -403,7 +403,6 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Khipha okuzenzakalelayo kokudlulisela ikhodi"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Nika amandla ukudlulisela ikhodi"</string>
<string name="transcode_default" msgid="3784803084573509491">"Kuthathe njengokungathi izinhlelo zokusebenza zisekela amafomethi esimanje"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"Nika amandla ukudlulisela ikhodi kwezinhlelo zokusebenza"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Amasevisi asebenzayo"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Buka futhi ulawule amasevisi asebenzayo okwamanje"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Ukufakwa ke-WebView"</string>
@@ -566,4 +565,29 @@
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Ama-headphone anentambo"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Vuliwe"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Valiwe"</string>
+ <string name="carrier_network_change_mode" msgid="4257621815706644026">"Inethiwekhi yenkampani yenethiwekhi iyashintsha"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+ <string name="data_connection_edge" msgid="4625509456544797637">"I-EDGE"</string>
+ <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+ <string name="data_connection_gprs" msgid="1251945769006770189">"I-GPRS"</string>
+ <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+ <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+ <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+ <string name="data_connection_lte" msgid="7675461204366364124">"I-LTE"</string>
+ <string name="data_connection_lte_plus" msgid="6643158654804916653">"I-LTE+"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"Idatha yeselula ivaliwe"</string>
+ <string name="not_default_data_content_description" msgid="6517068332106592887">"Akusethiwe ukuze kusetshenziswe idatha"</string>
+ <string name="accessibility_no_phone" msgid="2687419663127582503">"Ayikho ifoni."</string>
+ <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Ibha eyodwa yefoni"</string>
+ <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Amabha amabilil efoni."</string>
+ <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Amabha amathathu efoni"</string>
+ <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Isiginali yefoni igcwele"</string>
+ <string name="accessibility_no_data" msgid="4563181886936931008">"Ayikho idatha."</string>
+ <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Idatha enye yebha"</string>
+ <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Amabha amabili edatha"</string>
+ <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Amabha amathathu edatha"</string>
+ <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Igcwele i-signal yedatha"</string>
+ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"I-Ethernet inqanyuliwe."</string>
+ <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"I-Ethernet ixhunyiwe."</string>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java
index fc16eb6..61af5a7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java
@@ -22,16 +22,6 @@
public class MediaOutputSliceConstants {
/**
- * Key for the Media output setting.
- */
- public static final String KEY_MEDIA_OUTPUT = "media_output";
-
- /**
- * Key for the Media output group setting.
- */
- public static final String KEY_MEDIA_OUTPUT_GROUP = "media_output_group";
-
- /**
* Key for the Remote Media slice.
*/
public static final String KEY_REMOTE_MEDIA = "remote_media";
@@ -47,19 +37,6 @@
public static final String KEY_SESSION_INFO_ID = "key_session_info_id";
/**
- * Activity Action: Show a settings dialog containing {@link MediaDevice} to transfer media.
- */
- public static final String ACTION_MEDIA_OUTPUT =
- "com.android.settings.panel.action.MEDIA_OUTPUT";
-
- /**
- * Activity Action: Show a settings dialog containing {@link MediaDevice} to handle media group
- * operation.
- */
- public static final String ACTION_MEDIA_OUTPUT_GROUP =
- "com.android.settings.panel.action.MEDIA_OUTPUT_GROUP";
-
- /**
* A string extra specifying a media package name.
*/
public static final String EXTRA_PACKAGE_NAME =
@@ -72,12 +49,6 @@
"com.android.systemui.action.LAUNCH_MEDIA_OUTPUT_DIALOG";
/**
- * An intent action to dismiss media output dialog.
- */
- public static final String ACTION_DISMISS_MEDIA_OUTPUT_DIALOG =
- "com.android.systemui.action.DISMISS_MEDIA_OUTPUT_DIALOG";
-
- /**
* Settings package name.
*/
public static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 846efa7..6c51f2f 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -241,6 +241,12 @@
<!-- Default for setting for Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED -->
<bool name="def_hdmiControlAutoDeviceOff">false</bool>
+ <!-- Default for Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED -->
+ <bool name="def_swipe_bottom_to_notification_enabled">true</bool>
+
+ <!-- Default for Settings.Secure.ONE_HANDED_MODE_ENABLED -->
+ <bool name="def_one_handed_mode_enabled">false</bool>
+
<!-- Default for Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY -->
<integer name="def_accessibility_magnification_capabilities">3</integer>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index c9e3b6f..edb5506 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3342,7 +3342,7 @@
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 196;
+ private static final int SETTINGS_VERSION = 197;
private final int mUserId;
@@ -4786,6 +4786,35 @@
currentVersion = 196;
}
+ if (currentVersion == 196) {
+ // Version 196: Set the default value for Secure Settings:
+ // SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED & ONE_HANDED_MODE_ENABLED
+ final SettingsState secureSettings = getSecureSettingsLocked(userId);
+ final Setting swipeNotification = secureSettings.getSettingLocked(
+ Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED);
+ if (swipeNotification.isNull()) {
+ final boolean defSwipeNotification = getContext().getResources()
+ .getBoolean(R.bool.def_swipe_bottom_to_notification_enabled);
+ secureSettings.insertSettingLocked(
+ Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED,
+ defSwipeNotification ? "1" : "0", null, true,
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+
+ final Setting oneHandedModeEnabled = secureSettings.getSettingLocked(
+ Secure.ONE_HANDED_MODE_ENABLED);
+ if (oneHandedModeEnabled.isNull()) {
+ final boolean defOneHandedModeEnabled = getContext().getResources()
+ .getBoolean(R.bool.def_one_handed_mode_enabled);
+ secureSettings.insertSettingLocked(
+ Secure.ONE_HANDED_MODE_ENABLED,
+ defOneHandedModeEnabled ? "1" : "0", null, true,
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+
+ currentVersion = 197;
+ }
+
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 40b0fcff..53d868a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -42,6 +42,8 @@
import android.util.Slog;
import android.util.SparseIntArray;
import android.util.TimeUtils;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.util.proto.ProtoOutputStream;
@@ -52,7 +54,6 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileInputStream;
@@ -60,7 +61,6 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
@@ -806,13 +806,10 @@
try {
out = destination.startWrite();
- XmlSerializer serializer = Xml.newSerializer();
- serializer.setOutput(out, StandardCharsets.UTF_8.name());
- serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output",
- true);
+ TypedXmlSerializer serializer = Xml.resolveSerializer(out);
serializer.startDocument(null, true);
serializer.startTag(null, TAG_SETTINGS);
- serializer.attribute(null, ATTR_VERSION, String.valueOf(version));
+ serializer.attributeInt(null, ATTR_VERSION, version);
final int settingCount = settings.size();
for (int i = 0; i < settingCount; i++) {
@@ -908,7 +905,7 @@
}
}
- static void writeSingleSetting(int version, XmlSerializer serializer, String id,
+ static void writeSingleSetting(int version, TypedXmlSerializer serializer, String id,
String name, String value, String defaultValue, String packageName,
String tag, boolean defaultSysSet, boolean isValuePreservedInRestore)
throws IOException {
@@ -926,18 +923,18 @@
if (defaultValue != null) {
setValueAttribute(ATTR_DEFAULT_VALUE, ATTR_DEFAULT_VALUE_BASE64,
version, serializer, defaultValue);
- serializer.attribute(null, ATTR_DEFAULT_SYS_SET, Boolean.toString(defaultSysSet));
+ serializer.attributeBoolean(null, ATTR_DEFAULT_SYS_SET, defaultSysSet);
setValueAttribute(ATTR_TAG, ATTR_TAG_BASE64,
version, serializer, tag);
}
if (isValuePreservedInRestore) {
- serializer.attribute(null, ATTR_PRESERVE_IN_RESTORE, Boolean.toString(true));
+ serializer.attributeBoolean(null, ATTR_PRESERVE_IN_RESTORE, true);
}
serializer.endTag(null, TAG_SETTING);
}
static void setValueAttribute(String attr, String attrBase64, int version,
- XmlSerializer serializer, String value) throws IOException {
+ TypedXmlSerializer serializer, String value) throws IOException {
if (version >= SETTINGS_VERSION_NEW_ENCODING) {
if (value == null) {
// Null value -> No ATTR_VALUE nor ATTR_VALUE_BASE64.
@@ -956,7 +953,7 @@
}
}
- private static void writeSingleNamespaceHash(XmlSerializer serializer, String namespace,
+ private static void writeSingleNamespaceHash(TypedXmlSerializer serializer, String namespace,
String bannedHashCode) throws IOException {
if (namespace == null || bannedHashCode == null) {
return;
@@ -971,7 +968,7 @@
return Integer.toString(keyValues.hashCode());
}
- private String getValueAttribute(XmlPullParser parser, String attr, String base64Attr) {
+ private String getValueAttribute(TypedXmlPullParser parser, String attr, String base64Attr) {
if (mVersion >= SETTINGS_VERSION_NEW_ENCODING) {
final String value = parser.getAttributeValue(null, attr);
if (value != null) {
@@ -1039,8 +1036,7 @@
@GuardedBy("mLock")
private boolean parseStateFromXmlStreamLocked(FileInputStream in) {
try {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(in, StandardCharsets.UTF_8.name());
+ TypedXmlPullParser parser = Xml.resolvePullParser(in);
parseStateLocked(parser);
return true;
} catch (XmlPullParserException | IOException e) {
@@ -1060,7 +1056,7 @@
return stateFile.exists();
}
- private void parseStateLocked(XmlPullParser parser)
+ private void parseStateLocked(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
int type;
@@ -1080,10 +1076,10 @@
}
@GuardedBy("mLock")
- private void parseSettingsLocked(XmlPullParser parser)
+ private void parseSettingsLocked(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
- mVersion = Integer.parseInt(parser.getAttributeValue(null, ATTR_VERSION));
+ mVersion = parser.getAttributeInt(null, ATTR_VERSION);
final int outerDepth = parser.getDepth();
int type;
@@ -1101,14 +1097,12 @@
String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
String defaultValue = getValueAttribute(parser, ATTR_DEFAULT_VALUE,
ATTR_DEFAULT_VALUE_BASE64);
- String isPreservedInRestoreString = parser.getAttributeValue(null,
- ATTR_PRESERVE_IN_RESTORE);
- boolean isPreservedInRestore = Boolean.parseBoolean(isPreservedInRestoreString);
+ boolean isPreservedInRestore = parser.getAttributeBoolean(null,
+ ATTR_PRESERVE_IN_RESTORE, false);
String tag = null;
boolean fromSystem = false;
if (defaultValue != null) {
- fromSystem = Boolean.parseBoolean(parser.getAttributeValue(
- null, ATTR_DEFAULT_SYS_SET));
+ fromSystem = parser.getAttributeBoolean(null, ATTR_DEFAULT_SYS_SET, false);
tag = getValueAttribute(parser, ATTR_TAG, ATTR_TAG_BASE64);
}
mSettings.put(name, new Setting(name, value, defaultValue, packageName, tag,
@@ -1122,7 +1116,7 @@
}
@GuardedBy("mLock")
- private void parseNamespaceHash(XmlPullParser parser)
+ private void parseNamespaceHash(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
index 9f448af..69eb713 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
@@ -17,15 +17,13 @@
import android.os.Looper;
import android.test.AndroidTestCase;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
-import org.xmlpull.v1.XmlSerializer;
-
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
-import java.nio.charset.StandardCharsets;
public class SettingsStateTest extends AndroidTestCase {
public static final String CRAZY_STRING =
@@ -93,9 +91,7 @@
public void testWriteReadNoCrash() throws Exception {
ByteArrayOutputStream os = new ByteArrayOutputStream();
- XmlSerializer serializer = Xml.newSerializer();
- serializer.setOutput(os, StandardCharsets.UTF_8.name());
- serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ TypedXmlSerializer serializer = Xml.resolveSerializer(os);
serializer.startDocument(null, true);
for (int ch = 0; ch < 0x10000; ch++) {
@@ -118,12 +114,12 @@
serializer, "1", "k", "v", null, null, null, false, false);
}
- private void checkWriteSingleSetting(XmlSerializer serializer, String key, String value)
+ private void checkWriteSingleSetting(TypedXmlSerializer serializer, String key, String value)
throws Exception {
checkWriteSingleSetting(key + "/" + value, serializer, key, value);
}
- private void checkWriteSingleSetting(String msg, XmlSerializer serializer,
+ private void checkWriteSingleSetting(String msg, TypedXmlSerializer serializer,
String key, String value) throws Exception {
// Make sure the XML serializer won't crash.
SettingsState.writeSingleSetting(
diff --git a/packages/SystemUI/res/drawable/ic_fingerprint.xml b/packages/SystemUI/res/drawable/ic_fingerprint.xml
new file mode 100644
index 0000000..e5f3360
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_fingerprint.xml
@@ -0,0 +1,59 @@
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="32dp"
+ android:tint="?attr/wallpaperTextColor"
+ android:alpha=".75"
+ android:viewportHeight="32.0"
+ android:viewportWidth="32.0">
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M23.7,5.9c-0.1,0.0 -0.2,0.0 -0.3,-0.1C21.0,4.5 18.6,3.9 16.0,3.9c-2.5,0.0
+ -4.6,0.6 -6.9,1.9C8.8,6.0 8.3,5.9 8.1,5.5C7.9,5.2 8.0,4.7 8.4,4.5c2.5,-1.4 4.9,-2.1 7.7,
+ -2.1c2.8,0.0 5.4,0.7 8.0,2.1c0.4,0.2 0.5,0.6 0.3,1.0C24.2,5.7 24.0,5.9 23.7,5.9z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M5.3,13.2c-0.1,0.0 -0.3,0.0 -0.4,-0.1c-0.3,-0.2 -0.4,-0.7 -0.2,-1.0c1.3,
+ -1.9 2.9,-3.4 4.9,-4.5c4.1,-2.2 9.3,-2.2 13.4,0.0c1.9,1.1 3.6,2.5 4.9,4.4c0.2,0.3 0.1,0.8
+ -0.2,1.0c-0.3,0.2 -0.8,0.1 -1.0,-0.2c-1.2,-1.7 -2.6,-3.0 -4.3,-4.0c-3.7,-2.0 -8.3,-2.0
+ -12.0,0.0c-1.7,0.9 -3.2,2.3 -4.3,4.0C5.7,13.1 5.5,13.2 5.3,13.2z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M13.3,29.6c-0.2,0.0 -0.4,-0.1 -0.5,-0.2c-1.1,-1.2 -1.7,-2.0 -2.6,
+ -3.6c-0.9,-1.7 -1.4,-3.7 -1.4,-5.9c0.0,-4.1 3.3,-7.4 7.4,-7.4c4.1,0.0 7.4,3.3 7.4,7.4c0.0,
+ 0.4 -0.3,0.7 -0.7,0.7s-0.7,-0.3 -0.7,-0.7c0.0,-3.3 -2.7,-5.9 -5.9,-5.9c-3.3,0.0 -5.9,
+ 2.7 -5.9,5.9c0.0,2.0 0.4,3.8 1.2,5.2c0.8,1.6 1.4,2.2 2.4,3.3c0.3,0.3 0.3,0.8 0.0,1.0
+ C13.7,29.5 13.5,29.6 13.3,29.6z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M22.6,27.1c-1.6,0.0 -2.9,-0.4 -4.1,-1.2c-1.9,-1.4 -3.1,-3.6 -3.1,
+ -6.0c0.0,-0.4 0.3,-0.7 0.7,-0.7s0.7,0.3 0.7,0.7c0.0,1.9 0.9,3.7 2.5,4.8c0.9,0.6 1.9,
+ 1.0 3.2,1.0c0.3,0.0 0.8,0.0 1.3,-0.1c0.4,-0.1 0.8,0.2 0.8,0.6c0.1,0.4 -0.2,0.8 -0.6,
+ 0.8C23.4,27.1 22.8,27.1 22.6,27.1z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M20.0,29.9c-0.1,0.0 -0.1,0.0 -0.2,0.0c-2.1,-0.6 -3.4,-1.4 -4.8,-2.9c-1.8,
+ -1.9 -2.8,-4.4 -2.8,-7.1c0.0,-2.2 1.8,-4.1 4.1,-4.1c2.2,0.0 4.1,1.8 4.1,4.1c0.0,1.4 1.2,
+ 2.6 2.6,2.6c1.4,0.0 2.6,-1.2 2.6,-2.6c0.0,-5.1 -4.2,-9.3 -9.3,-9.3c-3.6,0.0 -6.9,2.1 -8.4,
+ 5.4C7.3,17.1 7.0,18.4 7.0,19.8c0.0,1.1 0.1,2.7 0.9,4.9c0.1,0.4 -0.1,0.8 -0.4,0.9c-0.4,
+ 0.1 -0.8,-0.1 -0.9,-0.4c-0.6,-1.8 -0.9,-3.6 -0.9,-5.4c0.0,-1.6 0.3,-3.1 0.9,-4.4c1.7,
+ -3.8 5.6,-6.3 9.8,-6.3c5.9,0.0 10.7,4.8 10.7,10.7c0.0,2.2 -1.8,4.1 -4.1,4.1s-4.0,
+ -1.8 -4.0,-4.1c0.0,-1.4 -1.2,-2.6 -2.6,-2.6c-1.4,0.0 -2.6,1.2 -2.6,2.6c0.0,2.3 0.9,
+ 4.5 2.4,6.1c1.2,1.3 2.4,2.0 4.2,2.5c0.4,0.1 0.6,0.5 0.5,0.9C20.6,29.7 20.3,29.9 20.0,
+ 29.9z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/people_space_small_avatar_tile.xml b/packages/SystemUI/res/layout/people_space_small_avatar_tile.xml
index 085e955..5aa0533 100644
--- a/packages/SystemUI/res/layout/people_space_small_avatar_tile.xml
+++ b/packages/SystemUI/res/layout/people_space_small_avatar_tile.xml
@@ -18,89 +18,177 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
- <LinearLayout
+ <RelativeLayout
android:background="@drawable/people_space_tile_view_card"
- android:id="@+id/item"
- android:orientation="vertical"
- android:paddingTop="6dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
- android:paddingHorizontal="12dp"
- android:paddingBottom="4dp"
- android:gravity="top"
android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <ImageView
- android:id="@+id/person_icon"
- android:layout_width="34dp"
- android:layout_height="34dp" />
-
+ android:layout_height="match_parent"
+ android:gravity="start">
+ <TextView
+ android:id="@+id/punctuation1"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+ android:textSize="36sp"
+ android:textStyle="bold"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="5dp"
+ android:maxLines="1"
+ android:alpha="0.2"
+ android:rotation="350" />
+ <TextView
+ android:id="@+id/punctuation2"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+ android:textSize="36sp"
+ android:textStyle="bold"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="25dp"
+ android:maxLines="1"
+ android:alpha="0.2"
+ android:rotation="5" />
+ <TextView
+ android:id="@+id/punctuation3"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+ android:textSize="36sp"
+ android:textStyle="bold"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="5dp"
+ android:layout_marginStart="25dp"
+ android:maxLines="1"
+ android:alpha="0.2"
+ android:rotation="355"/>
+ <TextView
+ android:id="@+id/punctuation4"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+ android:textSize="36sp"
+ android:textStyle="bold"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="-5dp"
+ android:layout_marginStart="25dp"
+ android:maxLines="1"
+ android:alpha="0.2"
+ android:rotation="10" />
+ <TextView
+ android:id="@+id/punctuation5"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+ android:textSize="36sp"
+ android:textStyle="bold"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="5dp"
+ android:layout_marginStart="25dp"
+ android:maxLines="1"
+ android:alpha="0.2"
+ android:rotation="15" />
+ <TextView
+ android:id="@+id/punctuation6"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+ android:textSize="36sp"
+ android:textStyle="bold"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="-5dp"
+ android:layout_marginStart="25dp"
+ android:maxLines="1"
+ android:alpha="0.2"
+ android:rotation="345" />
+ </LinearLayout>
+ <LinearLayout
+ android:id="@+id/item"
+ android:orientation="vertical"
+ android:paddingTop="6dp"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
<LinearLayout
- android:background="@drawable/people_space_rounded_border"
- android:layout_marginStart="-5dp"
- android:layout_marginTop="18dp"
- android:layout_width="8dp"
- android:layout_height="8dp">
-
- <ImageView
- android:id="@+id/package_icon"
- android:layout_width="6dp"
- android:layout_marginEnd="1dp"
- android:layout_marginStart="1dp"
- android:layout_marginBottom="1dp"
- android:layout_marginTop="1dp"
- android:layout_height="6dp" />
- </LinearLayout>
-
- <LinearLayout
- android:orientation="vertical"
- android:paddingStart="6dp"
+ android:orientation="horizontal"
+ android:paddingHorizontal="12dp"
+ android:paddingBottom="4dp"
+ android:gravity="top"
android:layout_width="match_parent"
android:layout_height="wrap_content">
- <TextView
- android:id="@+id/name"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="14sp"
- android:maxLines="1"
- android:ellipsize="end"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
+ <ImageView
+ android:id="@+id/person_icon"
+ android:layout_width="34dp"
+ android:layout_height="34dp" />
+ <LinearLayout
+ android:background="@drawable/people_space_rounded_border"
+ android:layout_marginStart="-5dp"
+ android:layout_marginTop="18dp"
+ android:layout_width="8dp"
+ android:layout_height="8dp">
+
+ <ImageView
+ android:id="@+id/package_icon"
+ android:layout_width="6dp"
+ android:layout_marginEnd="1dp"
+ android:layout_marginStart="1dp"
+ android:layout_marginBottom="1dp"
+ android:layout_marginTop="1dp"
+ android:layout_height="6dp" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:paddingStart="6dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/name"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="14sp"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:id="@+id/time"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+ android:textSize="10sp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxLines="1"
+ android:ellipsize="end" />
+ </LinearLayout>
+ </LinearLayout>
+ <LinearLayout
+ android:background="@drawable/people_space_content_background"
+ android:layout_gravity="center"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
<TextView
- android:id="@+id/time"
- android:textColor="?android:attr/textColorSecondary"
+ android:id="@+id/content"
+ android:paddingVertical="3dp"
+ android:paddingHorizontal="12dp"
+ android:gravity="center"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
- android:textSize="10sp"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:maxLines="1"
+ android:textSize="16sp"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:maxLines="2"
android:ellipsize="end" />
+ <ImageView
+ android:id="@+id/image"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone"/>
</LinearLayout>
</LinearLayout>
- <LinearLayout
- android:background="@drawable/people_space_content_background"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <TextView
- android:id="@+id/content"
- android:paddingVertical="3dp"
- android:paddingHorizontal="12dp"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
- android:textSize="14sp"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:maxLines="2"
- android:ellipsize="end" />
- <ImageView
- android:id="@+id/image"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:visibility="gone"/>
- </LinearLayout>
- </LinearLayout>
+ </RelativeLayout>
</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 84b9e3d..2c08f5d 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -18,6 +18,7 @@
<!-- extends FrameLayout -->
<com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/expandableNotificationRow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 52b93ee..6f69483 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -677,6 +677,8 @@
<dimen name="keyguard_clock_top_margin">36dp</dimen>
<!-- The margin between top of clock and bottom of lock icon. -->
<dimen name="keyguard_clock_lock_margin">16dp</dimen>
+ <!-- The amount to shift the clocks during a small/large transition -->
+ <dimen name="keyguard_clock_switch_y_shift">10dp</dimen>
<item name="scrim_behind_alpha" format="float" type="dimen">0.62</item>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 5435a15..0687d06 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2773,6 +2773,14 @@
<string name="basic_status" translatable="false">Open conversation</string>
<!-- Status for conversation without interaction data [CHAR LIMIT=120] -->
<string name="select_conversation_text" translatable="false">Select one conversation to show in your widget:</string>
+ <!-- Timestamp for notification with exact time [CHAR LIMIT=120] -->
+ <string name="timestamp" translatable="false"><xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string>
+ <!-- Timestamp for notification when less than a certain time window [CHAR LIMIT=120] -->
+ <string name="less_than_timestamp" translatable="false">Less than <xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string>
+ <!-- Timestamp for notification when over a certain time window [CHAR LIMIT=120] -->
+ <string name="over_timestamp" translatable="false">Over <xliff:g id="duration" example="1 week">%1$s</xliff:g> ago</string>
+ <!-- Status text for a birthday today [CHAR LIMIT=120] -->
+ <string name="birthday_status" translatable="false">Today is their birthday!</string>
<!-- Title to display in a notification when ACTION_BATTERY_CHANGED.EXTRA_PRESENT field is false
[CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index ab7ba8a..323449a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -1,6 +1,8 @@
package com.android.keyguard;
import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Paint;
@@ -48,6 +50,9 @@
*/
private static final float TO_BOLD_TRANSITION_FRACTION = 0.7f;
+ private static final long CLOCK_OUT_MILLIS = 150;
+ private static final long CLOCK_IN_MILLIS = 200;
+
/**
* Layout transition that scales the default clock face.
*/
@@ -112,6 +117,7 @@
private int[] mColorPalette;
private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
+ private int mClockSwitchYAmount;
public KeyguardClockSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -131,6 +137,17 @@
}
/**
+ * Apply dp changes on font/scale change
+ */
+ public void onDensityOrFontScaleChanged() {
+ setTextSize(TypedValue.COMPLEX_UNIT_PX, mContext.getResources()
+ .getDimensionPixelSize(R.dimen.widget_big_font_size));
+
+ mClockSwitchYAmount = mContext.getResources().getDimensionPixelSize(
+ R.dimen.keyguard_clock_switch_y_shift);
+ }
+
+ /**
* Returns if this view is presenting a custom clock, or the default implementation.
*/
public boolean hasCustomClock() {
@@ -181,6 +198,8 @@
mNewLockscreenLargeClockFrame = findViewById(R.id.new_lockscreen_clock_view_large);
mSmallClockFrame = findViewById(R.id.clock_view);
mKeyguardStatusArea = findViewById(R.id.keyguard_status_area);
+
+ onDensityOrFontScaleChanged();
}
void setClockPlugin(ClockPlugin plugin, int statusBarState) {
@@ -296,31 +315,43 @@
mClockViewBold.setFormat24Hour(format);
}
- private void updateClockLayout(boolean useLargeClock) {
+ private void animateClockChange(boolean useLargeClock) {
if (mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) return;
- Fade fadeIn = new Fade();
- fadeIn.setDuration(KeyguardSliceView.DEFAULT_ANIM_DURATION);
- fadeIn.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
-
- Fade fadeOut = new Fade();
- fadeOut.setDuration(KeyguardSliceView.DEFAULT_ANIM_DURATION / 2);
- fadeOut.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
-
+ View in, out;
+ int direction = 1;
if (useLargeClock) {
- TransitionManager.beginDelayedTransition(mNewLockscreenClockFrame, fadeOut);
- TransitionManager.beginDelayedTransition(mNewLockscreenLargeClockFrame, fadeIn);
-
- mNewLockscreenClockFrame.setVisibility(View.INVISIBLE);
- addView(mNewLockscreenLargeClockFrame);
- mNewLockscreenLargeClockFrame.setVisibility(View.VISIBLE);
+ out = mNewLockscreenClockFrame;
+ in = mNewLockscreenLargeClockFrame;
+ addView(in);
+ direction = -1;
} else {
- TransitionManager.beginDelayedTransition(mNewLockscreenClockFrame, fadeIn);
- TransitionManager.beginDelayedTransition(mNewLockscreenLargeClockFrame, fadeOut);
+ in = mNewLockscreenClockFrame;
+ out = mNewLockscreenLargeClockFrame;
- removeView(mNewLockscreenLargeClockFrame);
- mNewLockscreenClockFrame.setVisibility(View.VISIBLE);
+ // Must remove in order for notifications to appear in the proper place
+ removeView(out);
}
+
+ AnimatorSet outAnim = new AnimatorSet();
+ outAnim.setDuration(CLOCK_OUT_MILLIS);
+ outAnim.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
+ outAnim.playTogether(
+ ObjectAnimator.ofFloat(out, View.ALPHA, 0f),
+ ObjectAnimator.ofFloat(out, View.TRANSLATION_Y, 0,
+ direction * -mClockSwitchYAmount));
+
+ in.setAlpha(0);
+ in.setVisibility(View.VISIBLE);
+ AnimatorSet inAnim = new AnimatorSet();
+ inAnim.setDuration(CLOCK_IN_MILLIS);
+ inAnim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+ inAnim.playTogether(ObjectAnimator.ofFloat(in, View.ALPHA, 1f),
+ ObjectAnimator.ofFloat(in, View.TRANSLATION_Y, direction * mClockSwitchYAmount, 0));
+ inAnim.setStartDelay(CLOCK_OUT_MILLIS / 2);
+
+ inAnim.start();
+ outAnim.start();
}
/**
@@ -343,7 +374,8 @@
if (hasVisibleNotifications == mHasVisibleNotifications) {
return;
}
- updateClockLayout(!hasVisibleNotifications);
+
+ animateClockChange(!hasVisibleNotifications);
mHasVisibleNotifications = hasVisibleNotifications;
if (mDarkAmount == 0f && mBigClockContainer != null) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 4d6e8a9..e0de180 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -21,7 +21,6 @@
import android.content.res.Resources;
import android.provider.Settings;
import android.text.format.DateFormat;
-import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@@ -146,11 +145,10 @@
}
/**
- * Updates clock's text
+ * Apply dp changes on font/scale change
*/
public void onDensityOrFontScaleChanged() {
- mView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
- mResources.getDimensionPixelSize(R.dimen.widget_big_font_size));
+ mView.onDensityOrFontScaleChanged();
}
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 2071cfa..b43496c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1901,6 +1901,15 @@
}
/**
+ * Whether to show the lock icon on lock screen and bouncer. This depends on the enrolled
+ * biometrics to the device.
+ */
+ public boolean shouldShowLockIcon() {
+ return isFaceAuthEnabledForUser(KeyguardUpdateMonitor.getCurrentUser())
+ && !isUdfpsEnrolled();
+ }
+
+ /**
* @return true if there's at least one udfps enrolled
*/
public boolean isUdfpsEnrolled() {
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java
new file mode 100644
index 0000000..c0f8cae
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java
@@ -0,0 +1,109 @@
+/*
+ * 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.systemui;
+
+import android.annotation.NonNull;
+import android.app.Notification;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.statusbar.NotificationInteractionTracker;
+import com.android.systemui.statusbar.NotificationLifetimeExtender;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.util.time.SystemClock;
+
+import javax.inject.Inject;
+
+/**
+ * Extends the lifetime of foreground notification services such that they show for at least
+ * five seconds
+ */
+public class ForegroundServiceLifetimeExtender implements NotificationLifetimeExtender {
+
+ private static final String TAG = "FGSLifetimeExtender";
+ @VisibleForTesting
+ static final int MIN_FGS_TIME_MS = 5000;
+
+ private NotificationSafeToRemoveCallback mNotificationSafeToRemoveCallback;
+ private ArraySet<NotificationEntry> mManagedEntries = new ArraySet<>();
+ private Handler mHandler = new Handler(Looper.getMainLooper());
+ private final SystemClock mSystemClock;
+ private final NotificationInteractionTracker mInteractionTracker;
+
+ @Inject
+ public ForegroundServiceLifetimeExtender(
+ NotificationInteractionTracker interactionTracker,
+ SystemClock systemClock) {
+ mSystemClock = systemClock;
+ mInteractionTracker = interactionTracker;
+ }
+
+ @Override
+ public void setCallback(@NonNull NotificationSafeToRemoveCallback callback) {
+ mNotificationSafeToRemoveCallback = callback;
+ }
+
+ @Override
+ public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
+ if ((entry.getSbn().getNotification().flags
+ & Notification.FLAG_FOREGROUND_SERVICE) == 0) {
+ return false;
+ }
+
+ // Entry has triggered a HUN or some other interruption, therefore it has been seen and the
+ // interrupter might be retaining it anyway.
+ if (entry.hasInterrupted()) {
+ return false;
+ }
+
+ boolean hasInteracted = mInteractionTracker.hasUserInteractedWith(entry.getKey());
+ long aliveTime = mSystemClock.uptimeMillis() - entry.getCreationTime();
+ return aliveTime < MIN_FGS_TIME_MS && !hasInteracted;
+ }
+
+ @Override
+ public boolean shouldExtendLifetimeForPendingNotification(
+ @NonNull NotificationEntry entry) {
+ return shouldExtendLifetime(entry);
+ }
+
+ @Override
+ public void setShouldManageLifetime(
+ @NonNull NotificationEntry entry, boolean shouldManage) {
+ if (!shouldManage) {
+ mManagedEntries.remove(entry);
+ return;
+ }
+
+ mManagedEntries.add(entry);
+
+ Runnable r = () -> {
+ if (mManagedEntries.contains(entry)) {
+ mManagedEntries.remove(entry);
+ if (mNotificationSafeToRemoveCallback != null) {
+ mNotificationSafeToRemoveCallback.onSafeToRemove(entry.getKey());
+ }
+ }
+ };
+ long delayAmt = MIN_FGS_TIME_MS
+ - (mSystemClock.uptimeMillis() - entry.getCreationTime());
+ mHandler.postDelayed(r, delayAmt);
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
index 04e26d3..d6cb114 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
@@ -50,6 +50,7 @@
ForegroundServiceController foregroundServiceController,
NotificationEntryManager notificationEntryManager,
NotifPipeline notifPipeline,
+ ForegroundServiceLifetimeExtender fgsLifetimeExtender,
SystemClock systemClock) {
mContext = context;
mForegroundServiceController = foregroundServiceController;
@@ -77,6 +78,7 @@
removeNotification(entry.getSbn());
}
});
+ mEntryManager.addNotificationLifetimeExtender(fgsLifetimeExtender);
notifPipeline.addCollectionListener(new NotifCollectionListener() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index a15a5aa..65a6f29 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -135,7 +135,7 @@
@SuppressLint("ClickableViewAccessibility")
private final UdfpsView.OnTouchListener mOnTouchListener = (v, event) -> {
UdfpsView view = (UdfpsView) v;
- final boolean isFingerDown = view.isScrimShowing();
+ final boolean isFingerDown = view.isShowScrimAndDot();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
index 5a61379..663a0da 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
@@ -27,6 +27,7 @@
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -70,6 +71,7 @@
// mInsetsListener to restrict the touchable region and allow the touches outside of the sensor
// to propagate to the rest of the UI.
@NonNull private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener;
+ @NonNull private final Drawable mFingerprintDrawable;
// Used to obtain the sensor location.
@NonNull private FingerprintSensorPropertiesInternal mSensorProps;
@@ -79,7 +81,7 @@
private float mBurnInOffsetX;
private float mBurnInOffsetY;
- private boolean mIsScrimShowing;
+ private boolean mShowScrimAndDot;
private boolean mIsHbmSupported;
@Nullable private String mDebugMessage;
@@ -112,15 +114,16 @@
mSensorPaint = new Paint(0 /* flags */);
mSensorPaint.setAntiAlias(true);
mSensorPaint.setColor(Color.WHITE);
- mSensorPaint.setStyle(Paint.Style.STROKE);
- mSensorPaint.setStrokeWidth(SENSOR_OUTLINE_WIDTH);
mSensorPaint.setShadowLayer(SENSOR_SHADOW_RADIUS, 0, 0, Color.BLACK);
+ mSensorPaint.setStyle(Paint.Style.FILL);
mDebugTextPaint = new Paint();
mDebugTextPaint.setAntiAlias(true);
mDebugTextPaint.setColor(Color.BLUE);
mDebugTextPaint.setTextSize(DEBUG_TEXT_SIZE_PX);
+ mFingerprintDrawable = getResources().getDrawable(R.drawable.ic_fingerprint, null);
+
mTouchableRegion = new Rect();
// When the device is rotated, it's important that mTouchableRegion is updated before
// this listener is called. This listener is usually called shortly after onLayout.
@@ -130,7 +133,7 @@
internalInsetsInfo.touchableRegion.set(mTouchableRegion);
};
- mIsScrimShowing = false;
+ mShowScrimAndDot = false;
}
void setSensorProperties(@NonNull FingerprintSensorPropertiesInternal properties) {
@@ -181,6 +184,13 @@
default:
// Do nothing to stay in portrait mode.
}
+
+ int margin = (int) (mSensorRect.bottom - mSensorRect.top) / 5;
+ mFingerprintDrawable.setBounds(
+ (int) mSensorRect.left + margin,
+ (int) mSensorRect.top + margin,
+ (int) mSensorRect.right - margin,
+ (int) mSensorRect.bottom - margin);
}
@Override
@@ -198,6 +208,8 @@
// is finished, mTouchableRegion will be used by mInsetsListener to compute the touch
// insets.
mSensorRect.roundOut(mTouchableRegion);
+
+
}
@Override
@@ -218,7 +230,7 @@
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
- if (mIsScrimShowing && mIsHbmSupported) {
+ if (mShowScrimAndDot && mIsHbmSupported) {
// Only draw the scrim if HBM is supported.
canvas.drawRect(mScrimRect, mScrimPaint);
}
@@ -229,7 +241,15 @@
if (!TextUtils.isEmpty(mDebugMessage)) {
canvas.drawText(mDebugMessage, 0, 160, mDebugTextPaint);
}
- canvas.drawOval(mSensorRect, mSensorPaint);
+
+ if (mShowScrimAndDot) {
+ // draw dot (white circle)
+ canvas.drawOval(mSensorRect, mSensorPaint);
+ } else {
+ // draw fingerprint icon
+ mFingerprintDrawable.draw(canvas);
+ }
+
canvas.restore();
}
@@ -264,19 +284,17 @@
mScrimPaint.setAlpha(alpha);
}
- boolean isScrimShowing() {
- return mIsScrimShowing;
+ boolean isShowScrimAndDot() {
+ return mShowScrimAndDot;
}
void showScrimAndDot() {
- mIsScrimShowing = true;
- mSensorPaint.setStyle(Paint.Style.FILL);
+ mShowScrimAndDot = true;
invalidate();
}
void hideScrimAndDot() {
- mIsScrimShowing = false;
- mSensorPaint.setStyle(Paint.Style.STROKE);
+ mShowScrimAndDot = false;
invalidate();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt
index a7d17e1..b4137fa 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt
@@ -64,7 +64,8 @@
private val globalSettings: GlobalSettings,
private val systemSettings: SystemSettings,
private val mainHandler: Handler,
- private val dumpManager: DumpManager
+ private val dumpManager: DumpManager,
+ private val enabled: Boolean
) : Dumpable {
private var userDefinedBrightness: Float = 1f
@@ -86,7 +87,7 @@
return
}
// TODO enable only when receiving a low-light error
- overridingBrightness = running
+ overridingBrightness = if (enabled) running else false
}
}
private lateinit var whiteOverlay: View
@@ -188,6 +189,7 @@
println("brightnessAnimationDuration: $brightnessAnimationDuration")
println("maxScreenBrightness: $maxScreenBrightness")
println("userDefinedBrightness: $userDefinedBrightness")
+ println("enabled: $enabled")
}
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index d7b5eea..626abfc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -142,8 +142,9 @@
return Optional.empty();
}
+ // currently disabled (doesn't ramp up brightness or use scrim) see b/175918367
return Optional.of(new FaceAuthScreenBrightnessController(
notificationShadeWindowController, keyguardUpdateMonitor, resources,
- globalSetting, systemSettings, handler, dumpManager));
+ globalSetting, systemSettings, handler, dumpManager, false));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 9e25389..4f85192 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -94,7 +94,8 @@
public MediaOutputController(@NonNull Context context, String packageName,
boolean aboveStatusbar, MediaSessionManager mediaSessionManager, LocalBluetoothManager
lbm, ShadeController shadeController, ActivityStarter starter,
- NotificationEntryManager notificationEntryManager, UiEventLogger uiEventLogger) {
+ NotificationEntryManager notificationEntryManager, UiEventLogger uiEventLogger,
+ MediaRouter2Manager routerManager) {
mContext = context;
mPackageName = packageName;
mMediaSessionManager = mediaSessionManager;
@@ -106,7 +107,7 @@
mLocalMediaManager = new LocalMediaManager(mContext, lbm, imm, packageName);
mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName);
mUiEventLogger = uiEventLogger;
- mRouterManager = MediaRouter2Manager.getInstance(mContext);
+ mRouterManager = routerManager;
}
void start(@NonNull Callback cb) {
@@ -137,7 +138,9 @@
mLocalMediaManager.stopScan();
mLocalMediaManager.registerCallback(this);
mLocalMediaManager.startScan();
- mRouterManager.startScan();
+ if (mRouterManager != null) {
+ mRouterManager.startScan();
+ }
}
void stop() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
index 0f340a5..e1a504c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
@@ -18,6 +18,7 @@
import android.content.Context
import android.media.session.MediaSessionManager
+import android.media.MediaRouter2Manager
import com.android.internal.logging.UiEventLogger
import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.systemui.plugins.ActivityStarter
@@ -35,7 +36,8 @@
private val shadeController: ShadeController,
private val starter: ActivityStarter,
private val notificationEntryManager: NotificationEntryManager,
- private val uiEventLogger: UiEventLogger
+ private val uiEventLogger: UiEventLogger,
+ private val routerManager: MediaRouter2Manager
) {
companion object {
var mediaOutputDialog: MediaOutputDialog? = null
@@ -46,7 +48,7 @@
mediaOutputDialog?.dismiss()
mediaOutputDialog = MediaOutputController(context, packageName, aboveStatusBar,
mediaSessionManager, lbm, shadeController, starter, notificationEntryManager,
- uiEventLogger).run {
+ uiEventLogger, routerManager).run {
MediaOutputDialog(context, aboveStatusBar, this, uiEventLogger)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
index 62de939..2ad12b9 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
@@ -44,7 +44,6 @@
import com.android.systemui.people.widget.PeopleSpaceWidgetProvider;
import java.util.List;
-import java.util.Map;
/**
* Shows the user their tiles for their priority People (go/live-status).
@@ -96,13 +95,12 @@
*/
private void setTileViewsWithPriorityConversations() {
try {
- List<Map.Entry<Long, PeopleSpaceTile>> tiles = PeopleSpaceUtils.getTiles(
+ List<PeopleSpaceTile> tiles = PeopleSpaceUtils.getTiles(
mContext, mNotificationManager, mPeopleManager, mLauncherApps);
- for (Map.Entry<Long, PeopleSpaceTile> entry : tiles) {
- PeopleSpaceTile tile = entry.getValue();
+ for (PeopleSpaceTile tile : tiles) {
PeopleSpaceTileView tileView = new PeopleSpaceTileView(mContext, mPeopleSpaceLayout,
tile.getId());
- setTileView(tileView, tile, entry.getKey());
+ setTileView(tileView, tile);
}
} catch (Exception e) {
Log.e(TAG, "Couldn't retrieve conversations", e);
@@ -110,12 +108,12 @@
}
/** Sets {@code tileView} with the data in {@code conversation}. */
- private void setTileView(PeopleSpaceTileView tileView, PeopleSpaceTile tile,
- long lastInteraction) {
+ private void setTileView(PeopleSpaceTileView tileView, PeopleSpaceTile tile) {
try {
String pkg = tile.getPackageName();
String status =
- PeopleSpaceUtils.getLastInteractionString(mContext, lastInteraction);
+ PeopleSpaceUtils.getLastInteractionString(mContext,
+ tile.getLastInteractionTimestamp(), true);
tileView.setStatus(status);
tileView.setName(tile.getUserName().toString());
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
index 7fc24f6..f1a57bf 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
@@ -29,6 +29,8 @@
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.LauncherApps;
+import android.database.Cursor;
+import android.database.SQLException;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
@@ -41,7 +43,7 @@
import android.os.Parcelable;
import android.os.ServiceManager;
import android.os.UserHandle;
-import android.preference.PreferenceManager;
+import android.provider.ContactsContract;
import android.provider.Settings;
import android.service.notification.ConversationChannelWrapper;
import android.service.notification.StatusBarNotification;
@@ -49,21 +51,30 @@
import android.view.View;
import android.widget.RemoteViews;
+import androidx.preference.PreferenceManager;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.ArrayUtils;
+import com.android.settingslib.utils.ThreadUtils;
import com.android.systemui.R;
import com.android.systemui.people.widget.LaunchConversationActivity;
import com.android.systemui.people.widget.PeopleSpaceWidgetProvider;
+import java.text.SimpleDateFormat;
import java.time.Duration;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -77,6 +88,11 @@
private static final int ONE_DAY = 1;
public static final String OPTIONS_PEOPLE_SPACE_TILE = "options_people_space_tile";
+ private static final Pattern DOUBLE_EXCLAMATION_PATTERN = Pattern.compile("[!][!]+");
+ private static final Pattern DOUBLE_QUESTION_PATTERN = Pattern.compile("[?][?]+");
+ private static final Pattern ANY_DOUBLE_MARK_PATTERN = Pattern.compile("[!?][!?]+");
+ private static final Pattern MIXED_MARK_PATTERN = Pattern.compile("![?].*|.*[?]!");
+
/** Represents whether {@link StatusBarNotification} was posted or removed. */
public enum NotificationAction {
POSTED,
@@ -107,7 +123,7 @@
}
/** Returns a list of map entries corresponding to user's conversations. */
- public static List<Map.Entry<Long, PeopleSpaceTile>> getTiles(
+ public static List<PeopleSpaceTile> getTiles(
Context context, INotificationManager notificationManager, IPeopleManager peopleManager,
LauncherApps launcherApps)
throws Exception {
@@ -115,70 +131,72 @@
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 1;
List<ConversationChannelWrapper> conversations = notificationManager.getConversations(
true).getList();
- List<Map.Entry<Long, PeopleSpaceTile>> tiles = getSortedTiles(peopleManager,
- conversations.stream().map(c ->
- new PeopleSpaceTile.Builder(c.getShortcutInfo(), launcherApps).build()));
+ List<PeopleSpaceTile> tiles = getSortedTiles(peopleManager,
+ conversations.stream().filter(c -> c.getShortcutInfo() != null).map(
+ c -> new PeopleSpaceTile.Builder(c.getShortcutInfo(),
+ launcherApps).build()));
if (!showOnlyPriority) {
if (DEBUG) Log.d(TAG, "Add recent conversations");
List<ConversationChannel> recentConversations =
peopleManager.getRecentConversations().getList();
- List<Map.Entry<Long, PeopleSpaceTile>> recentTiles =
- getSortedTiles(peopleManager, recentConversations.stream().map(c ->
- new PeopleSpaceTile
- .Builder(c.getShortcutInfo(), launcherApps)
- .build()));
+ List<PeopleSpaceTile> recentTiles =
+ getSortedTiles(peopleManager,
+ recentConversations
+ .stream()
+ .filter(
+ c -> c.getShortcutInfo() != null)
+ .map(
+ c -> new PeopleSpaceTile.Builder(c.getShortcutInfo(),
+ launcherApps).build()));
tiles.addAll(recentTiles);
}
return tiles;
}
- /** Updates {@code appWidgetIds} with their associated conversation stored. */
+ /**
+ * Updates {@code appWidgetIds} with their associated conversation stored, handling a
+ * notification being posted or removed.
+ */
public static void updateSingleConversationWidgets(Context context, int[] appWidgetIds,
AppWidgetManager appWidgetManager, INotificationManager notificationManager) {
IPeopleManager peopleManager = IPeopleManager.Stub.asInterface(
ServiceManager.getService(Context.PEOPLE_SERVICE));
LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
+ Map<Integer, PeopleSpaceTile> widgetIdToTile = new HashMap<>();
try {
- List<Map.Entry<Long, PeopleSpaceTile>> tiles =
+ List<PeopleSpaceTile> tiles =
PeopleSpaceUtils.getTiles(context, notificationManager,
peopleManager, launcherApps);
-
for (int appWidgetId : appWidgetIds) {
String shortcutId = sp.getString(String.valueOf(appWidgetId), null);
if (DEBUG) {
- Log.d(TAG, "Set widget: " + appWidgetId + " with shortcut ID: " + shortcutId);
+ Log.d(TAG, "Widget ID: " + appWidgetId + " Shortcut ID: " + shortcutId);
}
- Optional<Map.Entry<Long, PeopleSpaceTile>> entry = tiles.stream().filter(
- e -> e.getValue().getId().equals(shortcutId)).findFirst();
+
+ Optional<PeopleSpaceTile> entry = tiles.stream().filter(
+ e -> e.getId().equals(shortcutId)).findFirst();
+
if (!entry.isPresent() || shortcutId == null) {
if (DEBUG) Log.d(TAG, "Matching conversation not found for shortcut ID");
//TODO: Delete app widget id when crash is fixed (b/175486868)
continue;
}
- PeopleSpaceTile tile =
- augmentTileFromStorage(entry.get().getValue(), appWidgetManager,
- appWidgetId);
-
- RemoteViews views = createRemoteViews(context, tile, entry.get().getKey(),
+ // Augment current tile based on stored fields.
+ PeopleSpaceTile tile = augmentTileFromStorage(entry.get(), appWidgetManager,
appWidgetId);
+ RemoteViews views = createRemoteViews(context, tile, appWidgetId);
+
// Tell the AppWidgetManager to perform an update on the current app widget.
appWidgetManager.updateAppWidget(appWidgetId, views);
+
+ widgetIdToTile.put(appWidgetId, tile);
}
} catch (Exception e) {
- Log.e(TAG, "Exception updating single conversation widgets: " + e);
+ Log.e(TAG, "Failed to retrieve conversations to set tiles: " + e);
}
- }
-
- /** Returns a list sorted by ascending last interaction time from {@code stream}. */
- private static List<Map.Entry<Long, PeopleSpaceTile>> getSortedTiles(
- IPeopleManager peopleManager, Stream<PeopleSpaceTile> stream) {
- return stream
- .filter(c -> shouldKeepConversation(c))
- .map(c -> Map.entry(getLastInteraction(peopleManager, c), c))
- .sorted((c1, c2) -> (c2.getKey().compareTo(c1.getKey())))
- .collect(Collectors.toList());
+ getBirthdaysOnBackgroundThread(context, appWidgetManager, widgetIdToTile, appWidgetIds);
}
/** Augment {@link PeopleSpaceTile} with fields from stored tile. */
@@ -191,6 +209,7 @@
return tile;
}
return tile.toBuilder()
+ .setStatusText(storedTile.getStatusText())
.setNotificationKey(storedTile.getNotificationKey())
.setNotificationContent(storedTile.getNotificationContent())
.setNotificationDataUri(storedTile.getNotificationDataUri())
@@ -227,37 +246,67 @@
.setNotificationDataUri(null)
.build();
}
+ updateAppWidgetOptions(appWidgetManager, appWidgetId, storedTile);
+ }
+
+ private static void updateAppWidgetOptions(AppWidgetManager appWidgetManager, int appWidgetId,
+ PeopleSpaceTile tile) {
Bundle newOptions = new Bundle();
- newOptions.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, storedTile);
+ newOptions.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, tile);
appWidgetManager.updateAppWidgetOptions(appWidgetId, newOptions);
}
- private static RemoteViews createRemoteViews(Context context, PeopleSpaceTile tile,
- long lastInteraction, int appWidgetId) throws Exception {
- // TODO: If key is null or if text and data uri are null.
- if (tile.getNotificationKey() == null) {
- return createLastInteractionRemoteViews(context, tile, lastInteraction, appWidgetId);
+ /** Creates a {@link RemoteViews} for {@code tile}. */
+ private static RemoteViews createRemoteViews(Context context,
+ PeopleSpaceTile tile, int appWidgetId) {
+ RemoteViews views;
+ if (tile.getNotificationKey() != null) {
+ views = createNotificationRemoteViews(context, tile);
+ } else if (tile.getStatusText() != null) {
+ views = createStatusRemoteViews(context, tile);
+ } else {
+ views = createLastInteractionRemoteViews(context, tile);
}
- return createNotificationRemoteViews(context, tile, lastInteraction, appWidgetId);
+ return setCommonRemoteViewsFields(context, views, tile, appWidgetId);
}
- private static RemoteViews createLastInteractionRemoteViews(Context context,
- PeopleSpaceTile tile, long lastInteraction, int appWidgetId)
- throws Exception {
- RemoteViews views = new RemoteViews(
- context.getPackageName(), R.layout.people_space_large_avatar_tile);
- String status = PeopleSpaceUtils.getLastInteractionString(
- context, lastInteraction);
- views.setTextViewText(R.id.status, status);
+ private static RemoteViews setCommonRemoteViewsFields(Context context, RemoteViews views,
+ PeopleSpaceTile tile, int appWidgetId) {
+ try {
+ views.setTextViewText(R.id.name, tile.getUserName().toString());
+ views.setImageViewBitmap(
+ R.id.package_icon,
+ PeopleSpaceUtils.convertDrawableToBitmap(
+ context.getPackageManager().getApplicationIcon(
+ tile.getPackageName())
+ )
+ );
+ views.setImageViewIcon(R.id.person_icon, tile.getUserIcon());
- views = setCommonRemoteViewsFields(context, views, tile, appWidgetId);
- return views;
+ Intent activityIntent = new Intent(context, LaunchConversationActivity.class);
+ activityIntent.addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_CLEAR_TASK
+ | Intent.FLAG_ACTIVITY_NO_HISTORY
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID, tile.getId());
+ activityIntent.putExtra(
+ PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME, tile.getPackageName());
+ activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_UID, tile.getUid());
+ views.setOnClickPendingIntent(R.id.item, PendingIntent.getActivity(
+ context,
+ appWidgetId,
+ activityIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE));
+ return views;
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to set common fields: " + e);
+ }
+ return null;
}
private static RemoteViews createNotificationRemoteViews(Context context,
- PeopleSpaceTile tile, long lastInteraction, int appWidgetId)
- throws Exception {
-
+ PeopleSpaceTile tile) {
RemoteViews views = new RemoteViews(
context.getPackageName(), R.layout.people_space_small_avatar_tile);
Uri image = tile.getNotificationDataUri();
@@ -267,46 +316,85 @@
views.setViewVisibility(R.id.image, View.VISIBLE);
views.setViewVisibility(R.id.content, View.GONE);
} else {
- views.setTextViewText(R.id.content, tile.getNotificationContent());
+ CharSequence content = tile.getNotificationContent();
+ views = setPunctuationRemoteViewsFields(views, content);
+ views.setTextViewText(R.id.content, content);
views.setViewVisibility(R.id.content, View.VISIBLE);
views.setViewVisibility(R.id.image, View.GONE);
}
-
- views = setCommonRemoteViewsFields(context, views, tile, appWidgetId);
+ views.setTextViewText(R.id.time, PeopleSpaceUtils.getLastInteractionString(
+ context, tile.getLastInteractionTimestamp(), false));
return views;
}
- private static RemoteViews setCommonRemoteViewsFields(
- Context context, RemoteViews views, PeopleSpaceTile tile, int appWidgetId)
- throws Exception {
- views.setTextViewText(R.id.name, tile.getUserName().toString());
- views.setImageViewBitmap(
- R.id.package_icon,
- PeopleSpaceUtils.convertDrawableToBitmap(
- context.getPackageManager().getApplicationIcon(tile.getPackageName())
- )
- );
- views.setImageViewIcon(R.id.person_icon, tile.getUserIcon());
-
- Intent activityIntent = new Intent(context, LaunchConversationActivity.class);
- activityIntent.addFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_CLEAR_TASK
- | Intent.FLAG_ACTIVITY_NO_HISTORY
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID, tile.getId());
- activityIntent.putExtra(
- PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME, tile.getPackageName());
- activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_UID, tile.getUid());
- views.setOnClickPendingIntent(R.id.item, PendingIntent.getActivity(
- context,
- appWidgetId,
- activityIntent,
- PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE));
+ private static RemoteViews createStatusRemoteViews(Context context,
+ PeopleSpaceTile tile) {
+ RemoteViews views = new RemoteViews(
+ context.getPackageName(), R.layout.people_space_large_avatar_tile);
+ views.setTextViewText(R.id.status, tile.getStatusText());
return views;
}
+ private static RemoteViews createLastInteractionRemoteViews(Context context,
+ PeopleSpaceTile tile) {
+ RemoteViews views = new RemoteViews(
+ context.getPackageName(), R.layout.people_space_large_avatar_tile);
+ String status = PeopleSpaceUtils.getLastInteractionString(
+ context, tile.getLastInteractionTimestamp(), true);
+ views.setTextViewText(R.id.status, status);
+ return views;
+ }
+
+ private static RemoteViews setPunctuationRemoteViewsFields(
+ RemoteViews views, CharSequence content) {
+ String punctuation = getBackgroundTextFromMessage(content.toString());
+ int visibility = View.GONE;
+ if (punctuation != null) {
+ visibility = View.VISIBLE;
+ }
+ views.setTextViewText(R.id.punctuation1, punctuation);
+ views.setTextViewText(R.id.punctuation2, punctuation);
+ views.setTextViewText(R.id.punctuation3, punctuation);
+ views.setTextViewText(R.id.punctuation4, punctuation);
+ views.setTextViewText(R.id.punctuation5, punctuation);
+ views.setTextViewText(R.id.punctuation6, punctuation);
+
+ views.setViewVisibility(R.id.punctuation1, visibility);
+ views.setViewVisibility(R.id.punctuation2, visibility);
+ views.setViewVisibility(R.id.punctuation3, visibility);
+ views.setViewVisibility(R.id.punctuation4, visibility);
+ views.setViewVisibility(R.id.punctuation5, visibility);
+ views.setViewVisibility(R.id.punctuation6, visibility);
+
+ return views;
+ }
+
+ /** Gets character for tile background decoration based on notification content. */
+ @VisibleForTesting
+ static String getBackgroundTextFromMessage(String message) {
+ if (!ANY_DOUBLE_MARK_PATTERN.matcher(message).find()) {
+ return null;
+ }
+ if (MIXED_MARK_PATTERN.matcher(message).find()) {
+ return "!?";
+ }
+ Matcher doubleQuestionMatcher = DOUBLE_QUESTION_PATTERN.matcher(message);
+ if (!doubleQuestionMatcher.find()) {
+ return "!";
+ }
+ Matcher doubleExclamationMatcher = DOUBLE_EXCLAMATION_PATTERN.matcher(message);
+ if (!doubleExclamationMatcher.find()) {
+ return "?";
+ }
+ // If we have both "!!" and "??", return the one that comes first.
+ if (doubleQuestionMatcher.start() < doubleExclamationMatcher.start()) {
+ return "?";
+ }
+ return "!";
+ }
+
/** Gets the most recent {@link Notification.MessagingStyle.Message} from the notification. */
+ @VisibleForTesting
public static Notification.MessagingStyle.Message getLastMessagingStyleMessage(
StatusBarNotification sbn) {
Notification notification = sbn.getNotification();
@@ -327,6 +415,18 @@
return null;
}
+ /** Returns a list sorted by ascending last interaction time from {@code stream}. */
+ private static List<PeopleSpaceTile> getSortedTiles(IPeopleManager peopleManager,
+ Stream<PeopleSpaceTile> stream) {
+ return stream
+ .filter(c -> shouldKeepConversation(c))
+ .map(c -> c.toBuilder().setLastInteractionTimestamp(
+ getLastInteraction(peopleManager, c)).build())
+ .sorted((c1, c2) -> new Long(c2.getLastInteractionTimestamp()).compareTo(
+ new Long(c1.getLastInteractionTimestamp())))
+ .collect(Collectors.toList());
+ }
+
/** Returns the last interaction time with the user specified by {@code PeopleSpaceTile}. */
private static Long getLastInteraction(IPeopleManager peopleManager,
PeopleSpaceTile tile) {
@@ -369,7 +469,8 @@
}
/** Returns a readable status describing the {@code lastInteraction}. */
- public static String getLastInteractionString(Context context, long lastInteraction) {
+ public static String getLastInteractionString(Context context, long lastInteraction,
+ boolean includeLastChatted) {
if (lastInteraction == 0L) {
Log.e(TAG, "Could not get valid last interaction");
return context.getString(R.string.basic_status);
@@ -379,18 +480,25 @@
MeasureFormat formatter = MeasureFormat.getInstance(Locale.getDefault(),
MeasureFormat.FormatWidth.WIDE);
if (durationSinceLastInteraction.toHours() < MIN_HOUR) {
- return context.getString(R.string.last_interaction_status_less_than,
+ return context.getString(includeLastChatted ? R.string.last_interaction_status_less_than
+ : R.string.less_than_timestamp,
formatter.formatMeasures(new Measure(MIN_HOUR, MeasureUnit.HOUR)));
} else if (durationSinceLastInteraction.toDays() < ONE_DAY) {
- return context.getString(R.string.last_interaction_status, formatter.formatMeasures(
- new Measure(durationSinceLastInteraction.toHours(), MeasureUnit.HOUR)));
+ return context.getString(
+ includeLastChatted ? R.string.last_interaction_status : R.string.timestamp,
+ formatter.formatMeasures(
+ new Measure(durationSinceLastInteraction.toHours(), MeasureUnit.HOUR)));
} else if (durationSinceLastInteraction.toDays() < DAYS_IN_A_WEEK) {
- return context.getString(R.string.last_interaction_status, formatter.formatMeasures(
- new Measure(durationSinceLastInteraction.toDays(), MeasureUnit.DAY)));
+ return context.getString(
+ includeLastChatted ? R.string.last_interaction_status : R.string.timestamp,
+ formatter.formatMeasures(
+ new Measure(durationSinceLastInteraction.toDays(), MeasureUnit.DAY)));
} else {
return context.getString(durationSinceLastInteraction.toDays() == DAYS_IN_A_WEEK
- ? R.string.last_interaction_status :
- R.string.last_interaction_status_over,
+ ? (includeLastChatted ? R.string.last_interaction_status :
+ R.string.timestamp) :
+ (includeLastChatted ? R.string.last_interaction_status_over
+ : R.string.over_timestamp),
formatter.formatMeasures(
new Measure(durationSinceLastInteraction.toDays() / DAYS_IN_A_WEEK,
MeasureUnit.WEEK)));
@@ -411,4 +519,139 @@
return tile != null && tile.getUserName().length() != 0;
}
+ private static boolean hasBirthdayStatus(PeopleSpaceTile tile, Context context) {
+ return tile.getStatusText() != null && tile.getStatusText().equals(
+ context.getString(R.string.birthday_status));
+ }
+
+
+ /** Calls to retrieve birthdays on a background thread. */
+ private static void getBirthdaysOnBackgroundThread(Context context,
+ AppWidgetManager appWidgetManager,
+ Map<Integer, PeopleSpaceTile> peopleSpaceTiles, int[] appWidgetIds) {
+ ThreadUtils.postOnBackgroundThread(
+ () -> getBirthdays(context, appWidgetManager, peopleSpaceTiles, appWidgetIds));
+ }
+
+ /** Queries the Contacts DB for any birthdays today. */
+ @VisibleForTesting
+ public static void getBirthdays(Context context, AppWidgetManager appWidgetManager,
+ Map<Integer, PeopleSpaceTile> widgetIdToTile, int[] appWidgetIds) {
+ if (DEBUG) Log.d(TAG, "Get birthdays");
+ if (appWidgetIds.length == 0) return;
+ List<String> lookupKeysWithBirthdaysToday = getContactLookupKeysWithBirthdaysToday(context);
+ for (int appWidgetId : appWidgetIds) {
+ PeopleSpaceTile storedTile = widgetIdToTile.get(appWidgetId);
+ if (storedTile == null || storedTile.getContactUri() == null) {
+ if (DEBUG) Log.d(TAG, "No contact uri for: " + storedTile);
+ removeBirthdayStatusIfPresent(appWidgetManager, context, storedTile, appWidgetId);
+ continue;
+ }
+ if (lookupKeysWithBirthdaysToday.isEmpty()) {
+ if (DEBUG) Log.d(TAG, "No birthdays today");
+ removeBirthdayStatusIfPresent(appWidgetManager, context, storedTile, appWidgetId);
+ continue;
+ }
+ updateTileWithBirthday(context, appWidgetManager, lookupKeysWithBirthdaysToday,
+ storedTile,
+ appWidgetId);
+ }
+ }
+
+ /** Removes the birthday status if present in {@code storedTile} and pushes the update. */
+ private static void removeBirthdayStatusIfPresent(AppWidgetManager appWidgetManager,
+ Context context, PeopleSpaceTile storedTile, int appWidgetId) {
+ if (hasBirthdayStatus(storedTile, context)) {
+ if (DEBUG) Log.d(TAG, "Remove " + storedTile.getUserName() + "'s birthday");
+ updateAppWidgetOptionsAndView(appWidgetManager, context, appWidgetId,
+ storedTile.toBuilder()
+ .setStatusText(null)
+ .build());
+ }
+ }
+
+ /**
+ * Update {@code storedTile} if the contact has a lookup key matched to any {@code
+ * lookupKeysWithBirthdays}.
+ */
+ private static void updateTileWithBirthday(Context context, AppWidgetManager appWidgetManager,
+ List<String> lookupKeysWithBirthdaysToday, PeopleSpaceTile storedTile,
+ int appWidgetId) {
+ Cursor cursor = null;
+ try {
+ cursor = context.getContentResolver().query(storedTile.getContactUri(),
+ null, null, null, null);
+ while (cursor != null && cursor.moveToNext()) {
+ String storedLookupKey = cursor.getString(
+ cursor.getColumnIndex(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY));
+ if (!storedLookupKey.isEmpty() && lookupKeysWithBirthdaysToday.contains(
+ storedLookupKey)) {
+ if (DEBUG) Log.d(TAG, storedTile.getUserName() + "'s birthday today!");
+ updateAppWidgetOptionsAndView(appWidgetManager, context, appWidgetId,
+ storedTile.toBuilder()
+ .setStatusText(context.getString(R.string.birthday_status))
+ .build());
+ return;
+ }
+ }
+ } catch (SQLException e) {
+ Log.e(TAG, "Failed to query contact: " + e);
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ removeBirthdayStatusIfPresent(appWidgetManager, context, storedTile, appWidgetId);
+ }
+
+ /** Update app widget options and the current view. */
+ private static void updateAppWidgetOptionsAndView(AppWidgetManager appWidgetManager,
+ Context context, int appWidgetId, PeopleSpaceTile tile) {
+ updateAppWidgetOptions(appWidgetManager, appWidgetId, tile);
+ RemoteViews views = createRemoteViews(context,
+ tile, appWidgetId);
+ appWidgetManager.updateAppWidget(appWidgetId, views);
+ }
+
+ /**
+ * Returns lookup keys for all contacts with a birthday today.
+ *
+ * <p>Birthdays are queried from a different table within the Contacts DB than the table for
+ * the Contact Uri provided by most messaging apps. Matching by the contact ID is then quite
+ * fragile as the row IDs across the different tables are not guaranteed to stay aligned, so we
+ * match the data by {@link ContactsContract.ContactsColumns#LOOKUP_KEY} key to ensure proper
+ * matching across all the Contacts DB tables.
+ */
+ private static List<String> getContactLookupKeysWithBirthdaysToday(Context context) {
+ List<String> lookupKeysWithBirthdaysToday = new ArrayList<>(1);
+ String today = new SimpleDateFormat("MM-dd").format(new Date());
+ String[] projection = new String[]{
+ ContactsContract.CommonDataKinds.Event.LOOKUP_KEY,
+ ContactsContract.CommonDataKinds.Event.START_DATE};
+ String where =
+ ContactsContract.Data.MIMETYPE
+ + "= ? AND " + ContactsContract.CommonDataKinds.Event.TYPE + "="
+ + ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY + " AND substr("
+ + ContactsContract.CommonDataKinds.Event.START_DATE + ",6) = ?";
+ String[] selection =
+ new String[]{ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE, today};
+ Cursor cursor = null;
+ try {
+ cursor = context.getContentResolver().query(ContactsContract.Data.CONTENT_URI,
+ projection, where, selection, null);
+ while (cursor != null && cursor.moveToNext()) {
+ String lookupKey = cursor.getString(
+ cursor.getColumnIndex(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY));
+ lookupKeysWithBirthdaysToday.add(lookupKey);
+ }
+ } catch (SQLException e) {
+ Log.e(TAG, "Failed to query birthdays: " + e);
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ return lookupKeysWithBirthdaysToday;
+ }
}
+
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
index 1e6c213..fb33aff 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
@@ -34,7 +34,6 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
/** People Space Widget RemoteViewsFactory class. */
public class PeopleSpaceWidgetRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
@@ -45,7 +44,7 @@
private INotificationManager mNotificationManager;
private PackageManager mPackageManager;
private LauncherApps mLauncherApps;
- private List<Map.Entry<Long, PeopleSpaceTile>> mTiles = new ArrayList<>();
+ private List<PeopleSpaceTile> mTiles = new ArrayList<>();
private Context mContext;
public PeopleSpaceWidgetRemoteViewsFactory(Context context, Intent intent) {
@@ -100,11 +99,10 @@
RemoteViews personView = new RemoteViews(mContext.getPackageName(),
R.layout.people_space_widget_item);
try {
- Map.Entry<Long, PeopleSpaceTile> entry = mTiles.get(i);
- PeopleSpaceTile tile = entry.getValue();
- long lastInteraction = entry.getKey();
+ PeopleSpaceTile tile = mTiles.get(i);
- String status = PeopleSpaceUtils.getLastInteractionString(mContext, lastInteraction);
+ String status = PeopleSpaceUtils.getLastInteractionString(mContext,
+ tile.getLastInteractionTimestamp(), true);
personView.setTextViewText(R.id.status, status);
personView.setTextViewText(R.id.name, tile.getUserName().toString());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 2076cbf..7ec2691 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -20,10 +20,8 @@
import static android.provider.Settings.Global.ZEN_MODE_OFF;
import android.app.Dialog;
-import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.ApplicationInfo;
@@ -53,7 +51,6 @@
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.SysUIToast;
-import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
@@ -78,17 +75,12 @@
private static final Intent ZEN_PRIORITY_SETTINGS =
new Intent(Settings.ACTION_ZEN_MODE_PRIORITY_SETTINGS);
- private static final String ACTION_SET_VISIBLE = "com.android.systemui.dndtile.SET_VISIBLE";
- private static final String EXTRA_VISIBLE = "visible";
-
private final ZenModeController mController;
private final DndDetailAdapter mDetailAdapter;
private final SharedPreferences mSharedPreferences;
- private final BroadcastDispatcher mBroadcastDispatcher;
private boolean mListening;
private boolean mShowingDetail;
- private boolean mReceiverRegistered;
@Inject
public DndTile(
@@ -100,7 +92,6 @@
ActivityStarter activityStarter,
QSLogger qsLogger,
ZenModeController zenModeController,
- BroadcastDispatcher broadcastDispatcher,
@Main SharedPreferences sharedPreferences
) {
super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
@@ -108,21 +99,9 @@
mController = zenModeController;
mSharedPreferences = sharedPreferences;
mDetailAdapter = new DndDetailAdapter();
- mBroadcastDispatcher = broadcastDispatcher;
- broadcastDispatcher.registerReceiver(mReceiver, new IntentFilter(ACTION_SET_VISIBLE));
- mReceiverRegistered = true;
mController.observe(getLifecycle(), mZenCallback);
}
- @Override
- protected void handleDestroy() {
- super.handleDestroy();
- if (mReceiverRegistered) {
- mBroadcastDispatcher.unregisterReceiver(mReceiver);
- mReceiverRegistered = false;
- }
- }
-
public static void setVisible(Context context, boolean visible) {
Prefs.putBoolean(context, Prefs.Key.DND_TILE_VISIBLE, visible);
}
@@ -348,15 +327,6 @@
}
};
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final boolean visible = intent.getBooleanExtra(EXTRA_VISIBLE, false);
- setVisible(mContext, visible);
- refreshState();
- }
- };
-
private final class DndDetailAdapter implements DetailAdapter, OnAttachStateChangeListener {
private ZenModePanel mZenPanel;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 7bac007..20efa32 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -197,7 +197,6 @@
viewState.hasItemsInStableShelf = lastViewState.inShelf;
viewState.hidden = !mAmbientState.isShadeExpanded()
|| mAmbientState.isQsCustomizerShowing();
- viewState.maxShelfEnd = maxShelfEnd;
} else {
viewState.hidden = true;
viewState.location = ExpandableViewState.LOCATION_GONE;
@@ -823,10 +822,6 @@
return - (getIntrinsicHeight() - mStatusBarHeight) / 2;
}
- public int getNotificationMergeSize() {
- return getIntrinsicHeight();
- }
-
@Override
public boolean hasNoContentHeight() {
return true;
@@ -1018,7 +1013,6 @@
private class ShelfState extends ExpandableViewState {
private float openedAmount;
private boolean hasItemsInStableShelf;
- private float maxShelfEnd;
@Override
public void applyToView(View view) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
index 998ae9e..c7ac403 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
@@ -30,8 +30,12 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.util.concurrency.DelayableExecutor;
+import java.util.HashMap;
+import java.util.Map;
+
import javax.inject.Inject;
/**
@@ -71,6 +75,9 @@
public void attach(NotifPipeline pipeline) {
mNotifPipeline = pipeline;
+ // extend the lifetime of foreground notification services to show for at least 5 seconds
+ mNotifPipeline.addNotificationLifetimeExtender(mForegroundLifetimeExtender);
+
// filter out foreground service notifications that aren't necessary anymore
mNotifPipeline.addPreGroupFilter(mNotifFilter);
@@ -112,6 +119,64 @@
};
/**
+ * Extends the lifetime of foreground notification services such that they show for at least
+ * five seconds
+ */
+ private final NotifLifetimeExtender mForegroundLifetimeExtender =
+ new NotifLifetimeExtender() {
+ private static final int MIN_FGS_TIME_MS = 5000;
+ private OnEndLifetimeExtensionCallback mEndCallback;
+ private Map<NotificationEntry, Runnable> mEndRunnables = new HashMap<>();
+
+ @Override
+ public String getName() {
+ return TAG;
+ }
+
+ @Override
+ public void setCallback(OnEndLifetimeExtensionCallback callback) {
+ mEndCallback = callback;
+ }
+
+ @Override
+ public boolean shouldExtendLifetime(NotificationEntry entry, int reason) {
+ if ((entry.getSbn().getNotification().flags
+ & Notification.FLAG_FOREGROUND_SERVICE) == 0) {
+ return false;
+ }
+
+ final long currTime = System.currentTimeMillis();
+ final boolean extendLife = currTime - entry.getSbn().getPostTime() < MIN_FGS_TIME_MS;
+
+ if (extendLife) {
+ if (!mEndRunnables.containsKey(entry)) {
+ final Runnable endExtensionRunnable = () -> {
+ mEndRunnables.remove(entry);
+ mEndCallback.onEndLifetimeExtension(
+ mForegroundLifetimeExtender,
+ entry);
+ };
+
+ final Runnable cancelRunnable = mMainExecutor.executeDelayed(
+ endExtensionRunnable,
+ MIN_FGS_TIME_MS - (currTime - entry.getSbn().getPostTime()));
+ mEndRunnables.put(entry, cancelRunnable);
+ }
+ }
+
+ return extendLife;
+ }
+
+ @Override
+ public void cancelLifetimeExtension(NotificationEntry entry) {
+ Runnable cancelRunnable = mEndRunnables.remove(entry);
+ if (cancelRunnable != null) {
+ cancelRunnable.run();
+ }
+ }
+ };
+
+ /**
* Puts foreground service notifications into its own section.
*/
private final NotifSectioner mNotifSectioner = new NotifSectioner("ForegroundService") {
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 0dc824f..9e8385b 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
@@ -632,10 +632,15 @@
if (DEBUG) {
int y = mTopPadding;
+ mDebugPaint.setColor(Color.RED);
canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
+
y = getLayoutHeight();
+ mDebugPaint.setColor(Color.YELLOW);
canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
+
y = getHeight() - getEmptyBottomMargin();
+ mDebugPaint.setColor(Color.GREEN);
canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 4ca9c5d..db0713c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -289,8 +289,6 @@
SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__HIDDEN);
mDismissCallbackRegistry.notifyDismissCancelled();
}
- mExpansion = EXPANSION_HIDDEN;
- dispatchExpansionChanged();
mIsScrimmed = false;
mFalsingCollector.onBouncerHidden();
mCallback.onBouncerVisiblityChanged(false /* shown */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index b9e8d74..6da5d1b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -164,10 +164,10 @@
public void setup(int statusBarMinHeight, int maxShadeBottom, int notificationStackHeight,
float panelExpansion, int parentHeight, int keyguardStatusHeight, int clockPreferredY,
boolean hasCustomClock, boolean hasVisibleNotifs, float dark, float emptyDragAmount,
- boolean bypassEnabled, int unlockedStackScrollerPadding, boolean udfpsEnrolled,
+ boolean bypassEnabled, int unlockedStackScrollerPadding, boolean showLockIcon,
float qsExpansion) {
- mMinTopMargin = statusBarMinHeight + (udfpsEnrolled ? mContainerTopPaddingWithoutLockIcon :
- mContainerTopPaddingWithLockIcon);
+ mMinTopMargin = statusBarMinHeight + (showLockIcon
+ ? mContainerTopPaddingWithLockIcon : mContainerTopPaddingWithoutLockIcon);
mMaxShadeBottom = maxShadeBottom;
mNotificationStackHeight = notificationStackHeight;
mPanelExpansion = panelExpansion;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
index 6bdc303..ab0366e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
@@ -501,7 +501,7 @@
if (mBlockUpdates && canBlockUpdates()) {
shouldUpdate = false;
}
- if (shouldUpdate && mLockIcon != null) {
+ if (shouldUpdate && mLockIcon != null && mLockIcon.getVisibility() != GONE) {
mLockIcon.update(state,
mStatusBarStateController.isDozing(), mKeyguardJustShown);
}
@@ -549,16 +549,14 @@
return false;
}
- if (mKeyguardUpdateMonitor.isUdfpsEnrolled()) {
- boolean changed = mLockIcon.getVisibility() == GONE;
+ if (!mKeyguardUpdateMonitor.shouldShowLockIcon()) {
+ boolean changed = mLockIcon.getVisibility() != GONE;
mLockIcon.setVisibility(GONE);
return changed;
}
boolean onAodOrDocked = mStatusBarStateController.isDozing() || mDocked;
- boolean invisible = onAodOrDocked || mWakeAndUnlockRunning || mShowingLaunchAffordance
- || (mKeyguardSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser())
- == KeyguardSecurityModel.SecurityMode.None);
+ boolean invisible = onAodOrDocked || mWakeAndUnlockRunning || mShowingLaunchAffordance;
boolean fingerprintOrBypass = mFingerprintUnlock
|| mKeyguardBypassController.getBypassEnabled();
if (fingerprintOrBypass && !mBouncerShowingScrimmed) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 8d3b128..ba08e76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -912,7 +912,8 @@
clockPreferredY, hasCustomClock(),
hasVisibleNotifications, mInterpolatedDarkAmount, mEmptyDragAmount,
bypassEnabled, getUnlockedStackScrollerPadding(),
- mUpdateMonitor.isUdfpsEnrolled(), getQsExpansionFraction());
+ mUpdateMonitor.shouldShowLockIcon(),
+ getQsExpansionFraction());
mClockPositionAlgorithm.run(mClockPositionResult);
mKeyguardStatusViewController.updatePosition(
mClockPositionResult.clockX, mClockPositionResult.clockY,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index ab96a6d..f8e361f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -1003,7 +1003,6 @@
}
private void updateThemeColors() {
- if (mScrimBehind == null) return;
int background = Utils.getColorAttr(mScrimBehind.getContext(),
android.R.attr.colorBackgroundFloating).getDefaultColor();
int accent = Utils.getColorAccent(mScrimBehind.getContext()).getDefaultColor();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java
index 272c494..22fd93e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java
@@ -25,11 +25,15 @@
import androidx.annotation.NonNull;
+import com.android.systemui.Dumpable;
+import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dump.DumpManager;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Date;
import javax.inject.Inject;
@@ -38,7 +42,7 @@
*/
@SysUISingleton
public class NextAlarmControllerImpl extends BroadcastReceiver
- implements NextAlarmController {
+ implements NextAlarmController, Dumpable {
private final ArrayList<NextAlarmChangeCallback> mChangeCallbacks = new ArrayList<>();
@@ -48,18 +52,34 @@
/**
*/
@Inject
- public NextAlarmControllerImpl(Context context) {
- mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ public NextAlarmControllerImpl(
+ AlarmManager alarmManager,
+ BroadcastDispatcher broadcastDispatcher,
+ DumpManager dumpManager) {
+ dumpManager.registerDumpable("NextAlarmController", this);
+ mAlarmManager = alarmManager;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
- context.registerReceiverAsUser(this, UserHandle.ALL, filter, null, null);
+ broadcastDispatcher.registerReceiver(this, filter, null, UserHandle.ALL);
updateNextAlarm();
}
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("NextAlarmController state:");
- pw.print(" mNextAlarm="); pw.println(mNextAlarm);
+ pw.print("mNextAlarm=");
+ if (mNextAlarm != null) {
+ pw.println(new Date(mNextAlarm.getTriggerTime()));
+ pw.print(" PendingIntentPkg=");
+ pw.println(mNextAlarm.getShowIntent().getCreatorPackage());
+ } else {
+ pw.println("null");
+ }
+
+ pw.println("Registered Callbacks:");
+ for (NextAlarmChangeCallback callback : mChangeCallbacks) {
+ pw.print(" "); pw.println(callback.toString());
+ }
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
index 6c3b37e..e967a5d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
@@ -24,7 +24,10 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+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;
import static org.mockito.Mockito.when;
@@ -51,6 +54,8 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.util.time.FakeSystemClock;
+import junit.framework.Assert;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -79,7 +84,8 @@
MockitoAnnotations.initMocks(this);
mFsc = new ForegroundServiceController(mAppOpsController, mMainHandler);
mListener = new ForegroundServiceNotificationListener(
- mContext, mFsc, mEntryManager, mNotifPipeline, mClock);
+ mContext, mFsc, mEntryManager, mNotifPipeline,
+ mock(ForegroundServiceLifetimeExtender.class), mClock);
ArgumentCaptor<NotificationEntryListener> entryListenerCaptor =
ArgumentCaptor.forClass(NotificationEntryListener.class);
verify(mEntryManager).addNotificationEntryListener(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java
new file mode 100644
index 0000000..9a40421
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.systemui;
+
+import static com.android.systemui.ForegroundServiceLifetimeExtender.MIN_FGS_TIME_MS;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Notification;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.systemui.statusbar.NotificationInteractionTracker;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ForegroundServiceNotificationListenerTest extends SysuiTestCase {
+ private ForegroundServiceLifetimeExtender mExtender;
+ private NotificationEntry mEntry;
+ private Notification mNotif;
+ private final FakeSystemClock mClock = new FakeSystemClock();
+
+ @Mock
+ private NotificationInteractionTracker mInteractionTracker;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mExtender = new ForegroundServiceLifetimeExtender(mInteractionTracker, mClock);
+
+ mNotif = new Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .setContentTitle("Title")
+ .setContentText("Text")
+ .build();
+
+ mEntry = new NotificationEntryBuilder()
+ .setCreationTime(mClock.uptimeMillis())
+ .setNotification(mNotif)
+ .build();
+ }
+
+ /**
+ * ForegroundServiceLifetimeExtenderTest
+ */
+ @Test
+ public void testShouldExtendLifetime_should_foreground() {
+ // Extend the lifetime of a FGS notification iff it has not been visible
+ // for the minimum time
+ mNotif.flags |= Notification.FLAG_FOREGROUND_SERVICE;
+
+ // No time has elapsed, keep showing
+ assertTrue(mExtender.shouldExtendLifetime(mEntry));
+ }
+
+ @Test
+ public void testShouldExtendLifetime_shouldNot_foreground() {
+ mNotif.flags |= Notification.FLAG_FOREGROUND_SERVICE;
+
+ // Entry was created at mClock.uptimeMillis(), advance it MIN_FGS_TIME_MS + 1
+ mClock.advanceTime(MIN_FGS_TIME_MS + 1);
+ assertFalse(mExtender.shouldExtendLifetime(mEntry));
+ }
+
+ @Test
+ public void testShouldExtendLifetime_shouldNot_notForeground() {
+ mNotif.flags = 0;
+
+ // Entry was created at mClock.uptimeMillis(), advance it MIN_FGS_TIME_MS + 1
+ mClock.advanceTime(MIN_FGS_TIME_MS + 1);
+ assertFalse(mExtender.shouldExtendLifetime(mEntry));
+ }
+
+ @Test
+ public void testShouldExtendLifetime_shouldNot_interruped() {
+ // GIVEN a notification that would trigger lifetime extension
+ mNotif.flags |= Notification.FLAG_FOREGROUND_SERVICE;
+
+ // GIVEN the notification has alerted
+ mEntry.setInterruption();
+
+ // THEN the notification does not need to have its lifetime extended by this extender
+ assertFalse(mExtender.shouldExtendLifetime(mEntry));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 648c319..7f8372e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -175,7 +175,7 @@
@Test
public void fingerDown() throws RemoteException {
// Configure UdfpsView to accept the ACTION_DOWN event
- when(mUdfpsView.isScrimShowing()).thenReturn(false);
+ when(mUdfpsView.isShowScrimAndDot()).thenReturn(false);
when(mUdfpsView.isValidTouch(anyFloat(), anyFloat(), anyFloat())).thenReturn(true);
// GIVEN that the overlay is showing
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt
index 73a7ca9..cb05a6b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt
@@ -83,7 +83,7 @@
MockitoAnnotations.initMocks(this)
faceAuthScreenBrightnessController = object : FaceAuthScreenBrightnessController(
notificationShadeWindowController, keyguardUpdateMonitor, resources, globalSettings,
- systemSettings, mainHandler, dumpManager) {
+ systemSettings, mainHandler, dumpManager, true) {
override fun createAnimator(start: Float, end: Float) = animator
}
`when`(systemSettings.getFloat(eq(SCREEN_BRIGHTNESS_FLOAT))).thenReturn(INITIAL_BRIGHTNESS)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index fd5d996..c00b394 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -24,6 +24,7 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.media.MediaRouter2Manager;
import android.media.session.MediaSessionManager;
import android.os.Bundle;
import android.testing.AndroidTestingRunner;
@@ -63,6 +64,7 @@
private NotificationEntryManager mNotificationEntryManager =
mock(NotificationEntryManager.class);
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
+ private final MediaRouter2Manager mRouterManager = mock(MediaRouter2Manager.class);
private MediaOutputBaseDialogImpl mMediaOutputBaseDialogImpl;
private MediaOutputController mMediaOutputController;
@@ -75,7 +77,7 @@
public void setUp() {
mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger);
+ mNotificationEntryManager, mUiEventLogger, mRouterManager);
mMediaOutputBaseDialogImpl = new MediaOutputBaseDialogImpl(mContext,
mMediaOutputController);
mMediaOutputBaseDialogImpl.onCreate(new Bundle());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
index d1a617b..c1a3994 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
@@ -32,6 +32,7 @@
import android.graphics.drawable.Icon;
import android.media.MediaDescription;
import android.media.MediaMetadata;
+import android.media.MediaRouter2Manager;
import android.media.RoutingSessionInfo;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
@@ -91,6 +92,7 @@
private NotificationEntryManager mNotificationEntryManager =
mock(NotificationEntryManager.class);
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
+ private final MediaRouter2Manager mRouter2Manager = mock(MediaRouter2Manager.class);
private Context mSpyContext;
private MediaOutputController mMediaOutputController;
@@ -113,7 +115,7 @@
mMediaOutputController = new MediaOutputController(mSpyContext, TEST_PACKAGE_NAME, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger);
+ mNotificationEntryManager, mUiEventLogger, mRouter2Manager);
mLocalMediaManager = spy(mMediaOutputController.mLocalMediaManager);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
MediaDescription.Builder builder = new MediaDescription.Builder();
@@ -157,7 +159,7 @@
public void start_withoutPackageName_verifyMediaControllerInit() {
mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger);
+ mNotificationEntryManager, mUiEventLogger, mRouter2Manager);
mMediaOutputController.start(mCb);
@@ -178,7 +180,7 @@
public void stop_withoutPackageName_verifyMediaControllerDeinit() {
mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger);
+ mNotificationEntryManager, mUiEventLogger, mRouter2Manager);
mMediaOutputController.start(mCb);
@@ -449,7 +451,7 @@
public void getNotificationLargeIcon_withoutPackageName_returnsNull() {
mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger);
+ mNotificationEntryManager, mUiEventLogger, mRouter2Manager);
assertThat(mMediaOutputController.getNotificationIcon()).isNull();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index 86f6bde..e47a5e7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -24,6 +24,7 @@
import static org.mockito.Mockito.when;
import android.media.MediaRoute2Info;
+import android.media.MediaRouter2Manager;
import android.media.session.MediaSessionManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -65,6 +66,7 @@
private final NotificationEntryManager mNotificationEntryManager =
mock(NotificationEntryManager.class);
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
+ private final MediaRouter2Manager mRouterManager = mock(MediaRouter2Manager.class);
private MediaOutputDialog mMediaOutputDialog;
private MediaOutputController mMediaOutputController;
@@ -74,7 +76,7 @@
public void setUp() {
mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger);
+ mNotificationEntryManager, mUiEventLogger, mRouterManager);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
mMediaOutputDialog = new MediaOutputDialog(mContext, false,
mMediaOutputController, mUiEventLogger);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
index c296ff5..6111099 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
@@ -21,6 +21,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import android.media.MediaRouter2Manager;
import android.media.session.MediaSessionManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -64,6 +65,7 @@
private NotificationEntryManager mNotificationEntryManager =
mock(NotificationEntryManager.class);
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
+ private final MediaRouter2Manager mRouterManager = mock(MediaRouter2Manager.class);
private MediaOutputGroupDialog mMediaOutputGroupDialog;
private MediaOutputController mMediaOutputController;
@@ -73,7 +75,7 @@
public void setUp() {
mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger);
+ mNotificationEntryManager, mUiEventLogger, mRouterManager);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
mMediaOutputGroupDialog = new MediaOutputGroupDialog(mContext, false,
mMediaOutputController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
index e934f84..644373c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
@@ -21,7 +21,13 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Notification;
@@ -29,11 +35,16 @@
import android.app.people.PeopleSpaceTile;
import android.appwidget.AppWidgetManager;
import android.content.ContentResolver;
+import android.content.Context;
import android.content.Intent;
+import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutInfo;
+import android.database.Cursor;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteException;
+import android.provider.ContactsContract;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
@@ -52,6 +63,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Map;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class PeopleSpaceUtilsTest extends SysuiTestCase {
@@ -61,6 +74,32 @@
private static final String SHORTCUT_ID = "101";
private static final String NOTIFICATION_KEY = "notification_key";
private static final String NOTIFICATION_CONTENT = "notification_content";
+ private static final String TEST_LOOKUP_KEY = "lookup_key";
+ private static final int TEST_COLUMN_INDEX = 1;
+ private static final Uri URI = Uri.parse("fake_uri");
+ private static final Icon ICON = Icon.createWithResource("package", R.drawable.ic_android);
+ private static final Person PERSON = new Person.Builder()
+ .setName("name")
+ .setKey("abc")
+ .setUri(URI.toString())
+ .setBot(false)
+ .build();
+ private static final PeopleSpaceTile PERSON_TILE =
+ new PeopleSpaceTile
+ .Builder(SHORTCUT_ID, "username", ICON, new Intent())
+ .setNotificationKey(NOTIFICATION_KEY)
+ .setNotificationContent(NOTIFICATION_CONTENT)
+ .setNotificationDataUri(URI)
+ .build();
+
+ private final ShortcutInfo mShortcutInfo = new ShortcutInfo.Builder(mContext,
+ SHORTCUT_ID).setLongLabel(
+ "name").setPerson(PERSON)
+ .build();
+ private final ShortcutInfo mShortcutInfoWithoutPerson = new ShortcutInfo.Builder(mContext,
+ SHORTCUT_ID).setLongLabel(
+ "name")
+ .build();
@Mock
private NotificationListener mListenerService;
@@ -68,26 +107,12 @@
private IAppWidgetService mIAppWidgetService;
@Mock
private AppWidgetManager mAppWidgetManager;
-
- private static Icon sIcon = Icon.createWithResource("package", R.drawable.ic_android);
- private static Uri sUri = new Uri.Builder()
- .scheme(ContentResolver.SCHEME_CONTENT)
- .authority("something")
- .path("test")
- .build();
- private static Person sPerson = new Person.Builder()
- .setName("name")
- .setKey("abc")
- .setUri("uri")
- .setBot(false)
- .build();
- private static PeopleSpaceTile sPeopleSpaceTile =
- new PeopleSpaceTile
- .Builder(SHORTCUT_ID, "username", sIcon, new Intent())
- .setNotificationKey(NOTIFICATION_KEY)
- .setNotificationContent(NOTIFICATION_CONTENT)
- .setNotificationDataUri(sUri)
- .build();
+ @Mock
+ private Cursor mMockCursor;
+ @Mock
+ private ContentResolver mMockContentResolver;
+ @Mock
+ private Context mMockContext;
@Before
public void setUp() throws RemoteException {
@@ -97,13 +122,19 @@
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
Bundle options = new Bundle();
- options.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, sPeopleSpaceTile);
+ options.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, PERSON_TILE);
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
when(mAppWidgetManager.getAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT)))
.thenReturn(options);
when(mAppWidgetManager.getAppWidgetOptions(eq(WIDGET_ID_WITHOUT_SHORTCUT)))
.thenReturn(new Bundle());
+
+ when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
+ when(mMockContentResolver.query(any(Uri.class), any(), anyString(), any(),
+ isNull())).thenReturn(mMockCursor);
+ when(mMockContext.getString(R.string.birthday_status)).thenReturn(
+ mContext.getString(R.string.birthday_status));
}
@Test
@@ -124,15 +155,104 @@
}
@Test
+ public void testGetBackgroundTextFromMessageNoPunctuation() {
+ String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage("test");
+
+ assertThat(backgroundText).isNull();
+ }
+
+ @Test
+ public void testGetBackgroundTextFromMessageSingleExclamation() {
+ String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage("test!");
+
+ assertThat(backgroundText).isNull();
+ }
+
+ @Test
+ public void testGetBackgroundTextFromMessageSingleQuestion() {
+ String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage("?test");
+
+ assertThat(backgroundText).isNull();
+ }
+
+ @Test
+ public void testGetBackgroundTextFromMessageSeparatedMarks() {
+ String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage("test! right!");
+
+ assertThat(backgroundText).isNull();
+ }
+
+ @Test
+ public void testGetBackgroundTextFromMessageDoubleExclamation() {
+ String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage("!!test");
+
+ assertThat(backgroundText).isEqualTo("!");
+ }
+
+ @Test
+ public void testGetBackgroundTextFromMessageDoubleQuestion() {
+ String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage("test??");
+
+ assertThat(backgroundText).isEqualTo("?");
+ }
+
+ @Test
+ public void testGetBackgroundTextFromMessageMixed() {
+ String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage("test?!");
+
+ assertThat(backgroundText).isEqualTo("!?");
+ }
+
+ @Test
+ public void testGetBackgroundTextFromMessageMixedInTheMiddle() {
+ String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage(
+ "test!? in the middle");
+
+ assertThat(backgroundText).isEqualTo("!?");
+ }
+
+ @Test
+ public void testGetBackgroundTextFromMessageMixedDifferentOrder() {
+ String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage(
+ "test!? in the middle");
+
+ assertThat(backgroundText).isEqualTo("!?");
+ }
+
+ @Test
+ public void testGetBackgroundTextFromMessageMultiple() {
+ String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage(
+ "test!?!!? in the middle");
+
+ assertThat(backgroundText).isEqualTo("!?");
+ }
+
+ @Test
+ public void testGetBackgroundTextFromMessageQuestionFirst() {
+ String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage(
+ "test?? in the middle!!");
+
+ assertThat(backgroundText).isEqualTo("?");
+ }
+
+ @Test
+ public void testGetBackgroundTextFromMessageExclamationFirst() {
+ String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage(
+ "test!! in the middle??");
+
+ assertThat(backgroundText).isEqualTo("!");
+ }
+
+ @Test
public void testGetLastMessagingStyleMessage() {
Notification notification = new Notification.Builder(mContext, "test")
.setContentTitle("TEST_TITLE")
.setContentText("TEST_TEXT")
.setShortcutId(SHORTCUT_ID)
- .setStyle(new Notification.MessagingStyle(sPerson)
- .addMessage(new Notification.MessagingStyle.Message("text1", 0, sPerson))
- .addMessage(new Notification.MessagingStyle.Message("text2", 20, sPerson))
- .addMessage(new Notification.MessagingStyle.Message("text3", 10, sPerson))
+ .setStyle(new Notification.MessagingStyle(PERSON)
+ .addMessage(new Notification.MessagingStyle.Message("text1", 0, PERSON))
+ .addMessage(new Notification.MessagingStyle.Message("text2", 20, PERSON))
+ .addMessage(new Notification.MessagingStyle.Message("text3", 10, PERSON))
)
.build();
StatusBarNotification sbn = new SbnBuilder()
@@ -149,21 +269,21 @@
public void testAugmentTileFromStorageWithNotification() {
PeopleSpaceTile tile =
new PeopleSpaceTile
- .Builder("id", "userName", sIcon, new Intent())
+ .Builder("id", "userName", ICON, new Intent())
.build();
PeopleSpaceTile actual = PeopleSpaceUtils
.augmentTileFromStorage(tile, mAppWidgetManager, WIDGET_ID_WITH_SHORTCUT);
assertThat(actual.getNotificationKey()).isEqualTo(NOTIFICATION_KEY);
assertThat(actual.getNotificationContent()).isEqualTo(NOTIFICATION_CONTENT);
- assertThat(actual.getNotificationDataUri()).isEqualTo(sUri);
+ assertThat(actual.getNotificationDataUri()).isEqualTo(URI);
}
@Test
public void testAugmentTileFromStorageWithoutNotification() {
PeopleSpaceTile tile =
new PeopleSpaceTile
- .Builder("id", "userName", sIcon, new Intent())
+ .Builder("id", "userName", ICON, new Intent())
.build();
PeopleSpaceTile actual = PeopleSpaceUtils
.augmentTileFromStorage(tile, mAppWidgetManager, WIDGET_ID_WITHOUT_SHORTCUT);
@@ -172,4 +292,98 @@
assertThat(actual.getNotificationKey()).isEqualTo(null);
assertThat(actual.getNotificationDataUri()).isEqualTo(null);
}
+
+ @Test
+ public void testDoNotUpdateSingleConversationAppWidgetWhenNotBirthday() {
+ int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT};
+ when(mMockCursor.moveToNext()).thenReturn(true, false);
+ when(mMockCursor.getString(eq(TEST_COLUMN_INDEX))).thenReturn(TEST_LOOKUP_KEY);
+ when(mMockCursor.getColumnIndex(eq(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY)
+ )).thenReturn(TEST_COLUMN_INDEX);
+
+ // Existing tile does not have birthday status.
+ Map<Integer, PeopleSpaceTile> widgetIdToTile = Map.of(WIDGET_ID_WITH_SHORTCUT,
+ new PeopleSpaceTile.Builder(mShortcutInfoWithoutPerson,
+ mContext.getSystemService(LauncherApps.class)).build());
+ PeopleSpaceUtils.getBirthdays(mMockContext, mAppWidgetManager,
+ widgetIdToTile, widgetIdsArray);
+
+ verify(mAppWidgetManager, never()).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
+ any());
+ }
+
+ @Test
+ public void testUpdateSingleConversationAppWidgetWithoutPersonContactUriToRemoveBirthday() {
+ int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT};
+ when(mMockCursor.moveToNext()).thenReturn(true, false);
+ when(mMockCursor.getString(eq(TEST_COLUMN_INDEX))).thenReturn(TEST_LOOKUP_KEY);
+ when(mMockCursor.getColumnIndex(eq(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY)
+ )).thenReturn(TEST_COLUMN_INDEX);
+
+ // Existing tile has a birthday status.
+ Map<Integer, PeopleSpaceTile> widgetIdToTile = Map.of(WIDGET_ID_WITH_SHORTCUT,
+ new PeopleSpaceTile.Builder(mShortcutInfoWithoutPerson,
+ mContext.getSystemService(LauncherApps.class)).setStatusText(
+ mContext.getString(R.string.birthday_status)).build());
+ PeopleSpaceUtils.getBirthdays(mMockContext, mAppWidgetManager,
+ widgetIdToTile, widgetIdsArray);
+
+ verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
+ any());
+ }
+
+ @Test
+ public void testUpdateSingleConversationAppWidgetToRemoveBirthdayWhenNoLongerBirthday() {
+ int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT};
+ Cursor mockPersonUriCursor = mock(Cursor.class);
+ Cursor mockBirthdaysUriCursor = mock(Cursor.class);
+ when(mockPersonUriCursor.moveToNext()).thenReturn(true, false);
+ when(mockBirthdaysUriCursor.moveToNext()).thenReturn(true, false);
+ when(mockBirthdaysUriCursor.getColumnIndex(
+ eq(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY)
+ )).thenReturn(TEST_COLUMN_INDEX);
+ when(mockPersonUriCursor.getColumnIndex(
+ eq(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY)
+ )).thenReturn(TEST_COLUMN_INDEX);
+ // Return different cursors based on the Uri queried.
+ when(mMockContentResolver.query(eq(URI), any(), any(), any(),
+ any())).thenReturn(mockPersonUriCursor);
+ when(mMockContentResolver.query(eq(ContactsContract.Data.CONTENT_URI), any(), any(), any(),
+ any())).thenReturn(mockBirthdaysUriCursor);
+ // Each cursor returns a different lookup key.
+ when(mockBirthdaysUriCursor.getString(eq(TEST_COLUMN_INDEX))).thenReturn(TEST_LOOKUP_KEY);
+ when(mockPersonUriCursor.getString(eq(TEST_COLUMN_INDEX))).thenReturn(
+ TEST_LOOKUP_KEY + "differentlookup");
+
+ // Existing tile has a birthday status.
+ Map<Integer, PeopleSpaceTile> widgetIdToTile = Map.of(WIDGET_ID_WITH_SHORTCUT,
+ new PeopleSpaceTile.Builder(mShortcutInfo,
+ mContext.getSystemService(LauncherApps.class)).setStatusText(
+ mContext.getString(R.string.birthday_status)).build());
+ PeopleSpaceUtils.getBirthdays(mMockContext, mAppWidgetManager,
+ widgetIdToTile, widgetIdsArray);
+
+ verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
+ any());
+ }
+
+ @Test
+ public void testUpdateSingleConversationAppWidgetWhenBirthday() {
+ int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT};
+ when(mMockCursor.moveToNext()).thenReturn(true, false, true, false);
+ when(mMockCursor.getString(eq(TEST_COLUMN_INDEX))).thenReturn(TEST_LOOKUP_KEY);
+ when(mMockCursor.getColumnIndex(eq(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY)
+ )).thenReturn(TEST_COLUMN_INDEX);
+
+ // Existing tile has a birthday status.
+ Map<Integer, PeopleSpaceTile> widgetIdToTile = Map.of(WIDGET_ID_WITH_SHORTCUT,
+ new PeopleSpaceTile.Builder(mShortcutInfo,
+ mContext.getSystemService(LauncherApps.class)).setStatusText(
+ mContext.getString(R.string.birthday_status)).build());
+ PeopleSpaceUtils.getBirthdays(mMockContext, mAppWidgetManager,
+ widgetIdToTile, widgetIdsArray);
+
+ verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
+ any());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
index cd4f51e..df07b12 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
@@ -37,7 +37,6 @@
import android.app.Person;
import android.app.people.PeopleSpaceTile;
import android.appwidget.AppWidgetManager;
-import android.content.ContentResolver;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ParceledListSlice;
@@ -95,6 +94,21 @@
private static final String OTHER_SHORTCUT_ID = "102";
private static final String NOTIFICATION_KEY = "notification_key";
private static final String NOTIFICATION_CONTENT = "notification_content";
+ private static final Uri URI = Uri.parse("fake_uri");
+ private static final Icon ICON = Icon.createWithResource("package", R.drawable.ic_android);
+ private static final Person PERSON = new Person.Builder()
+ .setName("name")
+ .setKey("abc")
+ .setUri(URI.toString())
+ .setBot(false)
+ .build();
+ private static final PeopleSpaceTile PERSON_TILE =
+ new PeopleSpaceTile
+ .Builder(SHORTCUT_ID, "username", ICON, new Intent())
+ .setNotificationKey(NOTIFICATION_KEY)
+ .setNotificationContent(NOTIFICATION_CONTENT)
+ .setNotificationDataUri(URI)
+ .build();
private PeopleSpaceWidgetManager mManager;
@@ -110,26 +124,6 @@
@Captor
private ArgumentCaptor<NotificationHandler> mListenerCaptor;
- private static Icon sIcon = Icon.createWithResource("package", R.drawable.ic_android);
- private static Uri sUri = new Uri.Builder()
- .scheme(ContentResolver.SCHEME_CONTENT)
- .authority("something")
- .path("test")
- .build();
- private static Person sPerson = new Person.Builder()
- .setName("name")
- .setKey("abc")
- .setUri("uri")
- .setBot(false)
- .build();
- private static PeopleSpaceTile sPeopleSpaceTile =
- new PeopleSpaceTile
- .Builder(SHORTCUT_ID, "username", sIcon, new Intent())
- .setNotificationKey(NOTIFICATION_KEY)
- .setNotificationContent(NOTIFICATION_CONTENT)
- .setNotificationDataUri(sUri)
- .build();
-
private final NoManSimulator mNoMan = new NoManSimulator();
private final FakeSystemClock mClock = new FakeSystemClock();
@@ -150,9 +144,9 @@
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
SharedPreferences.Editor editor = sp.edit();
editor.putString(String.valueOf(WIDGET_ID_WITH_SHORTCUT), SHORTCUT_ID);
- editor.commit();
+ editor.apply();
Bundle options = new Bundle();
- options.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, sPeopleSpaceTile);
+ options.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, PERSON_TILE);
when(mAppWidgetManager.getAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT)))
.thenReturn(options);
@@ -304,7 +298,6 @@
UserHandle.getUserHandleForUid(0), channel, IMPORTANCE_HIGH);
mClock.advanceTime(MIN_LINGER_DURATION);
- verify(mIAppWidgetService, never()).getAppWidgetIds(any());
verify(mIAppWidgetService, never()).notifyAppWidgetViewDataChanged(any(), any(), anyInt());
verify(mAppWidgetManager, never()).updateAppWidget(anyInt(),
any(RemoteViews.class));
@@ -456,8 +449,8 @@
.setContentTitle("TEST_TITLE")
.setContentText("TEST_TEXT")
.setShortcutId(shortcutId)
- .setStyle(new Notification.MessagingStyle(sPerson)
- .addMessage(new Notification.MessagingStyle.Message("text3", 10, sPerson))
+ .setStyle(new Notification.MessagingStyle(PERSON)
+ .addMessage(new Notification.MessagingStyle.Message("text3", 10, PERSON))
)
.build();
return new SbnBuilder()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java
index 0954621..639e791 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java
@@ -31,6 +31,7 @@
import android.app.Notification;
import android.os.Bundle;
import android.os.UserHandle;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -45,6 +46,7 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -69,6 +71,7 @@
private NotificationEntryBuilder mEntryBuilder;
private AppOpsCoordinator mAppOpsCoordinator;
private NotifFilter mForegroundFilter;
+ private NotifLifetimeExtender mForegroundNotifLifetimeExtender;
private NotifSectioner mFgsSection;
private FakeSystemClock mClock = new FakeSystemClock();
@@ -95,6 +98,13 @@
verify(mNotifPipeline, times(1)).addPreGroupFilter(filterCaptor.capture());
mForegroundFilter = filterCaptor.getValue();
+ // capture lifetime extender
+ ArgumentCaptor<NotifLifetimeExtender> lifetimeExtenderCaptor =
+ ArgumentCaptor.forClass(NotifLifetimeExtender.class);
+ verify(mNotifPipeline, times(1)).addNotificationLifetimeExtender(
+ lifetimeExtenderCaptor.capture());
+ mForegroundNotifLifetimeExtender = lifetimeExtenderCaptor.getValue();
+
mFgsSection = mAppOpsCoordinator.getSectioner();
}
@@ -150,6 +160,55 @@
}
@Test
+ public void extendLifetimeText_notForeground() {
+ // GIVEN the notification doesn't represent a foreground service
+ mEntryBuilder.modifyNotification(mContext)
+ .setFlag(FLAG_FOREGROUND_SERVICE, false);
+
+ // THEN don't extend the lifetime
+ assertFalse(mForegroundNotifLifetimeExtender
+ .shouldExtendLifetime(mEntryBuilder.build(),
+ NotificationListenerService.REASON_CLICK));
+ }
+
+ @Test
+ public void extendLifetimeText_foregroundNotifRecentlyPosted() {
+ // GIVEN the notification represents a foreground service that was just posted
+ Notification notification = new Notification.Builder(mContext, "test_channel")
+ .setFlag(FLAG_FOREGROUND_SERVICE, true)
+ .build();
+ NotificationEntry entry = mEntryBuilder
+ .setSbn(new StatusBarNotification(TEST_PKG, TEST_PKG, NOTIF_USER_ID, "",
+ NOTIF_USER_ID, NOTIF_USER_ID, notification,
+ new UserHandle(NOTIF_USER_ID), "", System.currentTimeMillis()))
+ .setNotification(notification)
+ .build();
+
+ // THEN extend the lifetime
+ assertTrue(mForegroundNotifLifetimeExtender
+ .shouldExtendLifetime(entry, NotificationListenerService.REASON_CLICK));
+ }
+
+ @Test
+ public void extendLifetimeText_foregroundNotifOld() {
+ // GIVEN the notification represents a foreground service that was posted 10 seconds ago
+ Notification notification = new Notification.Builder(mContext, "test_channel")
+ .setFlag(FLAG_FOREGROUND_SERVICE, true)
+ .build();
+ NotificationEntry entry = mEntryBuilder
+ .setSbn(new StatusBarNotification(TEST_PKG, TEST_PKG, NOTIF_USER_ID, "",
+ NOTIF_USER_ID, NOTIF_USER_ID, notification,
+ new UserHandle(NOTIF_USER_ID), "",
+ System.currentTimeMillis() - 10000))
+ .setNotification(notification)
+ .build();
+
+ // THEN don't extend the lifetime because the extended time exceeds MIN_FGS_TIME_MS
+ assertFalse(mForegroundNotifLifetimeExtender
+ .shouldExtendLifetime(entry, NotificationListenerService.REASON_CLICK));
+ }
+
+ @Test
public void testIncludeFGSInSection_importanceDefault() {
// GIVEN the notification represents a colorized foreground service with > min importance
mEntryBuilder
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
index 1ac7937..95a3505 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
@@ -91,6 +91,7 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
+ when(mKeyguardUpdateMonitor.shouldShowLockIcon()).thenReturn(true);
when(mLockIcon.getContext()).thenReturn(mContext);
mLockIconController = new LockscreenLockIconController(
mLockscreenGestureLogger, mKeyguardUpdateMonitor, mLockPatternUtils,
@@ -145,12 +146,10 @@
}
@Test
- public void testVisibility_noBouncer() {
- // no security (ie: no lock screen OR swipe to unlock)
- when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(
- KeyguardSecurityModel.SecurityMode.None);
+ public void testVisibility_doNotShowLockIcon() {
+ when(mKeyguardUpdateMonitor.shouldShowLockIcon()).thenReturn(false);
mOnAttachStateChangeListener.onViewAttachedToWindow(mLockIcon);
- verify(mLockIcon).updateIconVisibility(false);
+ verify(mLockIcon).setVisibility(View.GONE);
}
}
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
index 52a82dd..5ee30fb7 100644
--- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -51,7 +51,6 @@
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.nio.charset.StandardCharsets;
public class WallpaperBackupAgent extends BackupAgent {
private static final String TAG = "WallpaperBackup";
@@ -323,8 +322,7 @@
private Rect parseCropHint(File wallpaperInfo, String sectionTag) {
Rect cropHint = new Rect();
try (FileInputStream stream = new FileInputStream(wallpaperInfo)) {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(stream, StandardCharsets.UTF_8.name());
+ XmlPullParser parser = Xml.resolvePullParser(stream);
int type;
do {
@@ -351,8 +349,7 @@
private ComponentName parseWallpaperComponent(File wallpaperInfo, String sectionTag) {
ComponentName name = null;
try (FileInputStream stream = new FileInputStream(wallpaperInfo)) {
- final XmlPullParser parser = Xml.newPullParser();
- parser.setInput(stream, StandardCharsets.UTF_8.name());
+ final XmlPullParser parser = Xml.resolvePullParser(stream);
int type;
do {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 5d67992..2626654 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -120,8 +120,6 @@
AccessibilityUserState userState = mUserStateWeakReference.get();
if (userState == null) return;
userState.removeServiceLocked(this);
- userState.resetFocusAppearanceLocked();
- mSystemSupport.onClientChangeLocked(false);
mSystemSupport.getFullScreenMagnificationController().resetAllIfNeeded(mId);
mActivityTaskManagerService.setAllowAppSwitches(mComponentName.flattenToString(), -1,
userState.mUserId);
@@ -146,7 +144,6 @@
} finally {
Binder.restoreCallingIdentity(identity);
}
- userState.resetFocusAppearanceLocked();
mSystemSupport.onClientChangeLocked(false);
}
}
@@ -313,7 +310,6 @@
AccessibilityUserState userState = mUserStateWeakReference.get();
if (userState != null) {
userState.serviceDisconnectedLocked(this);
- userState.resetFocusAppearanceLocked();
}
resetLocked();
mSystemSupport.getFullScreenMagnificationController().resetAllIfNeeded(mId);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
index 90e2fdf..22efd37 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
@@ -194,7 +194,8 @@
mUserNonInteractiveUiTimeout = 0;
mUserInteractiveUiTimeout = 0;
mMagnificationMode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
- resetFocusAppearanceLocked();
+ mFocusStrokeWidth = mFocusStrokeWidthDefaultValue;
+ mFocusColor = mFocusColorDefaultValue;
}
void addServiceLocked(AccessibilityServiceConnection serviceConnection) {
@@ -924,13 +925,4 @@
mFocusStrokeWidth = strokeWidth;
mFocusColor = color;
}
-
- /**
- * Resets the stroke width and color of the focus rectangle to the default value.
- *
- */
- public void resetFocusAppearanceLocked() {
- mFocusStrokeWidth = mFocusStrokeWidthDefaultValue;
- mFocusColor = mFocusColorDefaultValue;
- }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java b/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
index a2c7e4f..bafb641 100644
--- a/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
+++ b/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
@@ -40,14 +40,10 @@
private final IAccessibilityInteractionConnectionCallback mServiceCallback;
private final IAccessibilityInteractionConnection mConnectionWithReplacementActions;
private final int mInteractionId;
- private final int mNodeWithReplacementActionsInteractionId;
private final Object mLock = new Object();
@GuardedBy("mLock")
- private boolean mRequestForNodeWithReplacementActionFailed;
-
- @GuardedBy("mLock")
- AccessibilityNodeInfo mNodeWithReplacementActions;
+ List<AccessibilityNodeInfo> mNodesWithReplacementActions;
@GuardedBy("mLock")
List<AccessibilityNodeInfo> mNodesFromOriginalWindow;
@@ -55,8 +51,18 @@
@GuardedBy("mLock")
AccessibilityNodeInfo mNodeFromOriginalWindow;
+ // Keep track of whether or not we've been called back for a single node
@GuardedBy("mLock")
- List<AccessibilityNodeInfo> mPrefetchedNodesFromOriginalWindow;
+ boolean mSingleNodeCallbackHappened;
+
+ // Keep track of whether or not we've been called back for multiple node
+ @GuardedBy("mLock")
+ boolean mMultiNodeCallbackHappened;
+
+ // We shouldn't get any more callbacks after we've called back the original service, but
+ // keep track to make sure we catch such strange things
+ @GuardedBy("mLock")
+ boolean mDone;
public ActionReplacingCallback(IAccessibilityInteractionConnectionCallback serviceCallback,
IAccessibilityInteractionConnection connectionWithReplacementActions,
@@ -64,20 +70,19 @@
mServiceCallback = serviceCallback;
mConnectionWithReplacementActions = connectionWithReplacementActions;
mInteractionId = interactionId;
- mNodeWithReplacementActionsInteractionId = interactionId + 1;
// Request the root node of the replacing window
final long identityToken = Binder.clearCallingIdentity();
try {
mConnectionWithReplacementActions.findAccessibilityNodeInfoByAccessibilityId(
- AccessibilityNodeInfo.ROOT_NODE_ID, null,
- mNodeWithReplacementActionsInteractionId, this, 0,
+ AccessibilityNodeInfo.ROOT_NODE_ID, null, interactionId + 1, this, 0,
interrogatingPid, interrogatingTid, null, null);
} catch (RemoteException re) {
if (DEBUG) {
Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
}
- mRequestForNodeWithReplacementActionFailed = true;
+ // Pretend we already got a (null) list of replacement nodes
+ mMultiNodeCallbackHappened = true;
} finally {
Binder.restoreCallingIdentity(identityToken);
}
@@ -85,73 +90,46 @@
@Override
public void setFindAccessibilityNodeInfoResult(AccessibilityNodeInfo info, int interactionId) {
- synchronized (mLock) {
+ boolean readyForCallback;
+ synchronized(mLock) {
if (interactionId == mInteractionId) {
mNodeFromOriginalWindow = info;
- } else if (interactionId == mNodeWithReplacementActionsInteractionId) {
- mNodeWithReplacementActions = info;
} else {
Slog.e(LOG_TAG, "Callback with unexpected interactionId");
return;
}
+
+ mSingleNodeCallbackHappened = true;
+ readyForCallback = mMultiNodeCallbackHappened;
}
- replaceInfoActionsAndCallServiceIfReady();
+ if (readyForCallback) {
+ replaceInfoActionsAndCallService();
+ }
}
@Override
public void setFindAccessibilityNodeInfosResult(List<AccessibilityNodeInfo> infos,
int interactionId) {
- synchronized (mLock) {
+ boolean callbackForSingleNode;
+ boolean callbackForMultipleNodes;
+ synchronized(mLock) {
if (interactionId == mInteractionId) {
mNodesFromOriginalWindow = infos;
- } else if (interactionId == mNodeWithReplacementActionsInteractionId) {
- setNodeWithReplacementActionsFromList(infos);
+ } else if (interactionId == mInteractionId + 1) {
+ mNodesWithReplacementActions = infos;
} else {
Slog.e(LOG_TAG, "Callback with unexpected interactionId");
return;
}
+ callbackForSingleNode = mSingleNodeCallbackHappened;
+ callbackForMultipleNodes = mMultiNodeCallbackHappened;
+ mMultiNodeCallbackHappened = true;
}
- replaceInfoActionsAndCallServiceIfReady();
- }
-
- @Override
- public void setPrefetchAccessibilityNodeInfoResult(List<AccessibilityNodeInfo> infos,
- int interactionId)
- throws RemoteException {
- synchronized (mLock) {
- if (interactionId == mInteractionId) {
- mPrefetchedNodesFromOriginalWindow = infos;
- } else {
- Slog.e(LOG_TAG, "Callback with unexpected interactionId");
- return;
- }
- }
- replaceInfoActionsAndCallServiceIfReady();
- }
-
- private void replaceInfoActionsAndCallServiceIfReady() {
- boolean originalAndReplacementCallsHaveHappened = false;
- synchronized (mLock) {
- originalAndReplacementCallsHaveHappened = mNodeWithReplacementActions != null
- && (mNodeFromOriginalWindow != null
- || mNodesFromOriginalWindow != null
- || mPrefetchedNodesFromOriginalWindow != null);
- originalAndReplacementCallsHaveHappened
- |= mRequestForNodeWithReplacementActionFailed;
- }
- if (originalAndReplacementCallsHaveHappened) {
+ if (callbackForSingleNode) {
replaceInfoActionsAndCallService();
- replaceInfosActionsAndCallService();
- replacePrefetchInfosActionsAndCallService();
}
- }
-
- private void setNodeWithReplacementActionsFromList(List<AccessibilityNodeInfo> infos) {
- for (int i = 0; i < infos.size(); i++) {
- AccessibilityNodeInfo info = infos.get(i);
- if (info.getSourceNodeId() == AccessibilityNodeInfo.ROOT_NODE_ID) {
- mNodeWithReplacementActions = info;
- }
+ if (callbackForMultipleNodes) {
+ replaceInfosActionsAndCallService();
}
}
@@ -165,10 +143,18 @@
private void replaceInfoActionsAndCallService() {
final AccessibilityNodeInfo nodeToReturn;
synchronized (mLock) {
+ if (mDone) {
+ if (DEBUG) {
+ Slog.e(LOG_TAG, "Extra callback");
+ }
+ return;
+ }
if (mNodeFromOriginalWindow != null) {
replaceActionsOnInfoLocked(mNodeFromOriginalWindow);
}
+ recycleReplaceActionNodesLocked();
nodeToReturn = mNodeFromOriginalWindow;
+ mDone = true;
}
try {
mServiceCallback.setFindAccessibilityNodeInfoResult(nodeToReturn, mInteractionId);
@@ -182,7 +168,21 @@
private void replaceInfosActionsAndCallService() {
final List<AccessibilityNodeInfo> nodesToReturn;
synchronized (mLock) {
- nodesToReturn = replaceActionsLocked(mNodesFromOriginalWindow);
+ if (mDone) {
+ if (DEBUG) {
+ Slog.e(LOG_TAG, "Extra callback");
+ }
+ return;
+ }
+ if (mNodesFromOriginalWindow != null) {
+ for (int i = 0; i < mNodesFromOriginalWindow.size(); i++) {
+ replaceActionsOnInfoLocked(mNodesFromOriginalWindow.get(i));
+ }
+ }
+ recycleReplaceActionNodesLocked();
+ nodesToReturn = (mNodesFromOriginalWindow == null)
+ ? null : new ArrayList<>(mNodesFromOriginalWindow);
+ mDone = true;
}
try {
mServiceCallback.setFindAccessibilityNodeInfosResult(nodesToReturn, mInteractionId);
@@ -193,31 +193,6 @@
}
}
- private void replacePrefetchInfosActionsAndCallService() {
- final List<AccessibilityNodeInfo> nodesToReturn;
- synchronized (mLock) {
- nodesToReturn = replaceActionsLocked(mPrefetchedNodesFromOriginalWindow);
- }
- try {
- mServiceCallback.setPrefetchAccessibilityNodeInfoResult(nodesToReturn, mInteractionId);
- } catch (RemoteException re) {
- if (DEBUG) {
- Slog.e(LOG_TAG, "Failed to setFindAccessibilityNodeInfosResult");
- }
- }
- }
-
- @GuardedBy("mLock")
- private List<AccessibilityNodeInfo> replaceActionsLocked(List<AccessibilityNodeInfo> infos) {
- if (infos != null) {
- for (int i = 0; i < infos.size(); i++) {
- replaceActionsOnInfoLocked(infos.get(i));
- }
- }
- return (infos == null)
- ? null : new ArrayList<>(infos);
- }
-
@GuardedBy("mLock")
private void replaceActionsOnInfoLocked(AccessibilityNodeInfo info) {
info.removeAllActions();
@@ -229,22 +204,40 @@
info.setDismissable(false);
// We currently only replace actions for the root node
if ((info.getSourceNodeId() == AccessibilityNodeInfo.ROOT_NODE_ID)
- && mNodeWithReplacementActions != null) {
- List<AccessibilityAction> actions = mNodeWithReplacementActions.getActionList();
- if (actions != null) {
- for (int j = 0; j < actions.size(); j++) {
- info.addAction(actions.get(j));
+ && mNodesWithReplacementActions != null) {
+ // This list should always contain a single node with the root ID
+ for (int i = 0; i < mNodesWithReplacementActions.size(); i++) {
+ AccessibilityNodeInfo nodeWithReplacementActions =
+ mNodesWithReplacementActions.get(i);
+ if (nodeWithReplacementActions.getSourceNodeId()
+ == AccessibilityNodeInfo.ROOT_NODE_ID) {
+ List<AccessibilityAction> actions = nodeWithReplacementActions.getActionList();
+ if (actions != null) {
+ for (int j = 0; j < actions.size(); j++) {
+ info.addAction(actions.get(j));
+ }
+ // The PIP needs to be able to take accessibility focus
+ info.addAction(AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS);
+ info.addAction(AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
+ }
+ info.setClickable(nodeWithReplacementActions.isClickable());
+ info.setFocusable(nodeWithReplacementActions.isFocusable());
+ info.setContextClickable(nodeWithReplacementActions.isContextClickable());
+ info.setScrollable(nodeWithReplacementActions.isScrollable());
+ info.setLongClickable(nodeWithReplacementActions.isLongClickable());
+ info.setDismissable(nodeWithReplacementActions.isDismissable());
}
- // The PIP needs to be able to take accessibility focus
- info.addAction(AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS);
- info.addAction(AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
}
- info.setClickable(mNodeWithReplacementActions.isClickable());
- info.setFocusable(mNodeWithReplacementActions.isFocusable());
- info.setContextClickable(mNodeWithReplacementActions.isContextClickable());
- info.setScrollable(mNodeWithReplacementActions.isScrollable());
- info.setLongClickable(mNodeWithReplacementActions.isLongClickable());
- info.setDismissable(mNodeWithReplacementActions.isDismissable());
}
}
+
+ @GuardedBy("mLock")
+ private void recycleReplaceActionNodesLocked() {
+ if (mNodesWithReplacementActions == null) return;
+ for (int i = mNodesWithReplacementActions.size() - 1; i >= 0; i--) {
+ AccessibilityNodeInfo nodeWithReplacementAction = mNodesWithReplacementActions.get(i);
+ nodeWithReplacementAction.recycle();
+ }
+ mNodesWithReplacementActions = null;
+ }
}
diff --git a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
index 2078492..002f6d7 100644
--- a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
+++ b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
@@ -183,7 +183,12 @@
} catch (PackageManager.NameNotFoundException e) {
Slog.w(TAG, "Failed to read allowAdbBackup property for + "
+ packageName);
- return false;
+
+ // This temporarily falls back to the legacy allowBackup flag to
+ // avoid breaking existing users of adb backup. Once they're able to use
+ // the new ALLOW_ADB_BACKUP property, we'll return false here.
+ // TODO(b/176088499): Return false here.
+ return allowBackup;
}
} else {
// All other apps can use adb backup only when running in debuggable mode.
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index f3d0a2e..70b2672 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -612,20 +612,25 @@
+ " for " + association
+ " - profile still present in " + otherAssociationWithDeviceProfile);
} else {
- mRoleManager.removeRoleHolderAsUser(
- association.getDeviceProfile(),
- association.getPackageName(),
- RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP,
- UserHandle.of(association.getUserId()),
- getContext().getMainExecutor(),
- success -> {
- if (!success) {
- Log.e(LOG_TAG, "Failed to revoke device profile role "
- + association.getDeviceProfile()
- + " to " + association.getPackageName()
- + " for user " + association.getUserId());
- }
- });
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mRoleManager.removeRoleHolderAsUser(
+ association.getDeviceProfile(),
+ association.getPackageName(),
+ RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP,
+ UserHandle.of(association.getUserId()),
+ getContext().getMainExecutor(),
+ success -> {
+ if (!success) {
+ Log.e(LOG_TAG, "Failed to revoke device profile role "
+ + association.getDeviceProfile()
+ + " to " + association.getPackageName()
+ + " for user " + association.getUserId());
+ }
+ });
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 9b99199..01ef69b 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -144,6 +144,7 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.INetworkActivityListener;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
@@ -1380,8 +1381,11 @@
return;
}
final String action = blocked ? "BLOCKED" : "UNBLOCKED";
+ final NetworkRequest satisfiedRequest = nri.getSatisfiedRequest();
+ final int requestId = satisfiedRequest != null
+ ? satisfiedRequest.requestId : nri.mRequests.get(0).requestId;
mNetworkInfoBlockingLogs.log(String.format(
- "%s %d(%d) on netId %d", action, nri.mUid, nri.request.requestId, net.getNetId()));
+ "%s %d(%d) on netId %d", action, nri.mUid, requestId, net.getNetId()));
}
/**
@@ -1709,16 +1713,17 @@
return newNc;
}
- Binder.withCleanCallingIdentity(
- () -> {
- if (!mLocationPermissionChecker.checkLocationPermission(
- callerPkgName, null /* featureId */, callerUid, null /* message */)) {
- // Caller does not have the requisite location permissions. Reset the
- // owner's UID in the NetworkCapabilities.
- newNc.setOwnerUid(INVALID_UID);
- }
- }
- );
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (!mLocationPermissionChecker.checkLocationPermission(
+ callerPkgName, null /* featureId */, callerUid, null /* message */)) {
+ // Caller does not have the requisite location permissions. Reset the
+ // owner's UID in the NetworkCapabilities.
+ newNc.setOwnerUid(INVALID_UID);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
return newNc;
}
@@ -1798,7 +1803,8 @@
private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() {
@Override
- public void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos) {
+ public void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos,
+ int uid) {
int deviceType = Integer.parseInt(label);
sendDataActivityBroadcast(deviceType, active, tsNanos);
}
@@ -2336,6 +2342,31 @@
}
/**
+ * Start listening for default data network activity state changes.
+ */
+ @Override
+ public void registerNetworkActivityListener(@NonNull INetworkActivityListener l) {
+ // TODO: Replace network activity listener registry in ConnectivityManager from NMS to here
+ }
+
+ /**
+ * Stop listening for default data network activity state changes.
+ */
+ @Override
+ public void unregisterNetworkActivityListener(@NonNull INetworkActivityListener l) {
+ // TODO: Replace network activity listener registry in ConnectivityManager from NMS to here
+ }
+
+ /**
+ * Check whether the default network radio is currently active.
+ */
+ @Override
+ public boolean isDefaultNetworkActive() {
+ // TODO: Replace isNetworkActive() in NMS.
+ return false;
+ }
+
+ /**
* Setup data activity tracking for the given network.
*
* Every {@code setupDataActivityTracking} should be paired with a
@@ -2705,7 +2736,7 @@
* Return an array of all current NetworkRequest sorted by request id.
*/
@VisibleForTesting
- protected NetworkRequestInfo[] requestsSortedById() {
+ NetworkRequestInfo[] requestsSortedById() {
NetworkRequestInfo[] requests = new NetworkRequestInfo[0];
requests = mNetworkRequests.values().toArray(requests);
// Sort the array based off the NRI containing the min requestId in its requests.
@@ -3555,30 +3586,58 @@
return false;
}
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
- if (reason == UnneededFor.LINGER && nri.request.isBackgroundRequest()) {
+ if (reason == UnneededFor.LINGER
+ && !nri.isMultilayerRequest()
+ && nri.mRequests.get(0).isBackgroundRequest()) {
// Background requests don't affect lingering.
continue;
}
- // If this Network is already the highest scoring Network for a request, or if
- // there is hope for it to become one if it validated, then it is needed.
- if (nri.request.isRequest() && nai.satisfies(nri.request) &&
- (nai.isSatisfyingRequest(nri.request.requestId) ||
- // Note that this catches two important cases:
- // 1. Unvalidated cellular will not be reaped when unvalidated WiFi
- // is currently satisfying the request. This is desirable when
- // cellular ends up validating but WiFi does not.
- // 2. Unvalidated WiFi will not be reaped when validated cellular
- // is currently satisfying the request. This is desirable when
- // WiFi ends up validating and out scoring cellular.
- nri.mSatisfier.getCurrentScore()
- < nai.getCurrentScoreAsValidated())) {
+ if (isNetworkPotentialSatisfier(nai, nri)) {
return false;
}
}
return true;
}
+ private boolean isNetworkPotentialSatisfier(
+ @NonNull final NetworkAgentInfo candidate, @NonNull final NetworkRequestInfo nri) {
+ // listen requests won't keep up a network satisfying it. If this is not a multilayer
+ // request, we can return immediately. For multilayer requests, we have to check to see if
+ // any of the multilayer requests may have a potential satisfier.
+ if (!nri.isMultilayerRequest() && nri.mRequests.get(0).isListen()) {
+ return false;
+ }
+ for (final NetworkRequest req : nri.mRequests) {
+ // As non-multilayer listen requests have already returned, the below would only happen
+ // for a multilayer request therefore continue to the next request if available.
+ if (req.isListen()) {
+ continue;
+ }
+ // If this Network is already the highest scoring Network for a request, or if
+ // there is hope for it to become one if it validated, then it is needed.
+ if (candidate.satisfies(req)) {
+ // As soon as a network is found that satisfies a request, return. Specifically for
+ // multilayer requests, returning as soon as a NetworkAgentInfo satisfies a request
+ // is important so as to not evaluate lower priority requests further in
+ // nri.mRequests.
+ final boolean isNetworkNeeded = candidate.isSatisfyingRequest(req.requestId)
+ // Note that this catches two important cases:
+ // 1. Unvalidated cellular will not be reaped when unvalidated WiFi
+ // is currently satisfying the request. This is desirable when
+ // cellular ends up validating but WiFi does not.
+ // 2. Unvalidated WiFi will not be reaped when validated cellular
+ // is currently satisfying the request. This is desirable when
+ // WiFi ends up validating and out scoring cellular.
+ || nri.mSatisfier.getCurrentScore()
+ < candidate.getCurrentScoreAsValidated();
+ return isNetworkNeeded;
+ }
+ }
+
+ return false;
+ }
+
private NetworkRequestInfo getNriForAppRequest(
NetworkRequest request, int callingUid, String requestedOperation) {
final NetworkRequestInfo nri = mNetworkRequests.get(request);
@@ -3875,8 +3934,12 @@
new CaptivePortal(new CaptivePortalImpl(network).asBinder()));
appIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
- Binder.withCleanCallingIdentity(() ->
- mContext.startActivityAsUser(appIntent, UserHandle.CURRENT));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mContext.startActivityAsUser(appIntent, UserHandle.CURRENT);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
private class CaptivePortalImpl extends ICaptivePortal.Stub {
@@ -5464,6 +5527,10 @@
this(r, null);
}
+ boolean isMultilayerRequest() {
+ return mRequests.size() > 1;
+ }
+
private List<NetworkRequest> initializeRequests(NetworkRequest r) {
final ArrayList<NetworkRequest> tempRequests = new ArrayList<>();
tempRequests.add(new NetworkRequest(r));
@@ -5505,7 +5572,7 @@
public void binderDied() {
log("ConnectivityService NetworkRequestInfo binderDied(" +
mRequests + ", " + mBinder + ")");
- releaseNetworkRequest(mRequests);
+ releaseNetworkRequests(mRequests);
}
@Override
@@ -5538,13 +5605,15 @@
mAppOpsManager.checkPackage(callerUid, callerPackageName);
}
- private ArrayList<Integer> getSignalStrengthThresholds(NetworkAgentInfo nai) {
+ private ArrayList<Integer> getSignalStrengthThresholds(@NonNull final NetworkAgentInfo nai) {
final SortedSet<Integer> thresholds = new TreeSet<>();
synchronized (nai) {
- for (NetworkRequestInfo nri : mNetworkRequests.values()) {
- if (nri.request.networkCapabilities.hasSignalStrength() &&
- nai.satisfiesImmutableCapabilitiesOf(nri.request)) {
- thresholds.add(nri.request.networkCapabilities.getSignalStrength());
+ for (final NetworkRequestInfo nri : mNetworkRequests.values()) {
+ for (final NetworkRequest req : nri.mRequests) {
+ if (req.networkCapabilities.hasSignalStrength()
+ && nai.satisfiesImmutableCapabilitiesOf(req)) {
+ thresholds.add(req.networkCapabilities.getSignalStrength());
+ }
}
}
}
@@ -5831,7 +5900,7 @@
return mNextNetworkProviderId.getAndIncrement();
}
- private void releaseNetworkRequest(List<NetworkRequest> networkRequests) {
+ private void releaseNetworkRequests(List<NetworkRequest> networkRequests) {
for (int i = 0; i < networkRequests.size(); i++) {
releaseNetworkRequest(networkRequests.get(i));
}
@@ -7763,10 +7832,13 @@
final int userId = UserHandle.getCallingUserId();
- Binder.withCleanCallingIdentity(() -> {
+ final long token = Binder.clearCallingIdentity();
+ try {
final IpMemoryStore ipMemoryStore = IpMemoryStore.getMemoryStore(mContext);
ipMemoryStore.factoryReset();
- });
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
// Turn airplane mode off
setAirplaneMode(false);
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index dbf179a..ea1ac0c 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -839,6 +839,17 @@
}
};
+ // Make <this> a copy of <orig>. The presumption is that <this> is empty.
+ protected void doCopy(IntentResolver orig) {
+ mFilters.addAll(orig.mFilters);
+ mTypeToFilter.putAll(orig.mTypeToFilter);
+ mBaseTypeToFilter.putAll(orig.mBaseTypeToFilter);
+ mWildTypeToFilter.putAll(orig.mWildTypeToFilter);
+ mSchemeToFilter.putAll(orig.mSchemeToFilter);
+ mActionToFilter.putAll(orig.mActionToFilter);
+ mTypedActionToFilter.putAll(orig.mTypedActionToFilter);
+ }
+
/**
* All filters that have been registered.
*/
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 636da6f..d30adf1 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -396,22 +396,12 @@
* Notify our observers of a change in the data activity state of the interface
*/
private void notifyInterfaceClassActivity(int type, boolean isActive, long tsNanos,
- int uid, boolean fromRadio) {
+ int uid) {
final boolean isMobile = ConnectivityManager.isNetworkTypeMobile(type);
int powerState = isActive
? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
: DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
if (isMobile) {
- if (!fromRadio) {
- if (mMobileActivityFromRadio) {
- // If this call is not coming from a report from the radio itself, but we
- // have previously received reports from the radio, then we will take the
- // power state to just be whatever the radio last reported.
- powerState = mLastPowerStateFromRadio;
- }
- } else {
- mMobileActivityFromRadio = true;
- }
if (mLastPowerStateFromRadio != powerState) {
mLastPowerStateFromRadio = powerState;
try {
@@ -431,15 +421,9 @@
}
}
- if (!isMobile || fromRadio || !mMobileActivityFromRadio) {
- // Report the change in data activity. We don't do this if this is a change
- // on the mobile network, that is not coming from the radio itself, and we
- // have previously seen change reports from the radio. In that case only
- // the radio is the authority for the current state.
- final boolean active = isActive;
- invokeForAllObservers(o -> o.interfaceClassDataActivityChanged(
- Integer.toString(type), active, tsNanos));
- }
+ final boolean active = isActive;
+ invokeForAllObservers(o -> o.interfaceClassDataActivityChanged(
+ Integer.toString(type), active, tsNanos, uid));
boolean report = false;
synchronized (mIdleTimerLock) {
@@ -671,7 +655,7 @@
timestampNanos = timestamp;
}
mDaemonHandler.post(() ->
- notifyInterfaceClassActivity(label, isActive, timestampNanos, uid, false));
+ notifyInterfaceClassActivity(label, isActive, timestampNanos, uid));
}
@Override
@@ -1157,7 +1141,7 @@
mNetworkActive = false;
}
mDaemonHandler.post(() -> notifyInterfaceClassActivity(type, true,
- SystemClock.elapsedRealtimeNanos(), -1, false));
+ SystemClock.elapsedRealtimeNanos(), -1));
}
}
@@ -1181,7 +1165,7 @@
}
mActiveIdleTimers.remove(iface);
mDaemonHandler.post(() -> notifyInterfaceClassActivity(params.type, false,
- SystemClock.elapsedRealtimeNanos(), -1, false));
+ SystemClock.elapsedRealtimeNanos(), -1));
}
}
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index 655d8ab..e8687e5 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -107,23 +107,23 @@
String ifacePrefix = isTun ? TEST_TUN_PREFIX : TEST_TAP_PREFIX;
String iface = ifacePrefix + sTestTunIndex.getAndIncrement();
- return Binder.withCleanCallingIdentity(
- () -> {
- try {
- ParcelFileDescriptor tunIntf =
- ParcelFileDescriptor.adoptFd(jniCreateTunTap(isTun, iface));
- for (LinkAddress addr : linkAddrs) {
- mNetd.interfaceAddAddress(
- iface,
- addr.getAddress().getHostAddress(),
- addr.getPrefixLength());
- }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ ParcelFileDescriptor tunIntf =
+ ParcelFileDescriptor.adoptFd(jniCreateTunTap(isTun, iface));
+ for (LinkAddress addr : linkAddrs) {
+ mNetd.interfaceAddAddress(
+ iface,
+ addr.getAddress().getHostAddress(),
+ addr.getPrefixLength());
+ }
- return new TestNetworkInterface(tunIntf, iface);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- });
+ return new TestNetworkInterface(tunIntf, iface);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
/**
@@ -317,7 +317,12 @@
try {
// This requires NETWORK_STACK privileges.
- Binder.withCleanCallingIdentity(() -> mNMS.setInterfaceUp(iface));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mNMS.setInterfaceUp(iface);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
// Synchronize all accesses to mTestNetworkTracker to prevent the case where:
// 1. TestNetworkAgent successfully binds to death of binder
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 165b6a1..74e3851 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -25,24 +25,44 @@
import android.net.NetworkRequest;
import android.net.vcn.IVcnManagementService;
import android.net.vcn.VcnConfig;
+import android.os.Binder;
+import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.ParcelUuid;
+import android.os.PersistableBundle;
+import android.os.Process;
+import android.os.ServiceSpecificException;
+import android.os.UserHandle;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
+import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
/**
* VcnManagementService manages Virtual Carrier Network profiles and lifecycles.
*
* <pre>The internal structure of the VCN Management subsystem is as follows:
*
- * +------------------------+ 1:1 +--------------------------------+
- * | VcnManagementService | ------------ Creates -------------> | TelephonySubscriptionManager |
- * | | | |
- * | Manages configs and | | Tracks subscriptions, carrier |
- * | VcnInstance lifecycles | <--- Notifies of subscription & --- | privilege changes, caches maps |
- * +------------------------+ carrier privilege changes +--------------------------------+
+ * +-------------------------+ 1:1 +--------------------------------+
+ * | VcnManagementService | ------------ Creates ------------> | TelephonySubscriptionManager |
+ * | | | |
+ * | Manages configs and | | Tracks subscriptions, carrier |
+ * | Vcn instance lifecycles | <--- Notifies of subscription & -- | privilege changes, caches maps |
+ * +-------------------------+ carrier privilege changes +--------------------------------+
* | 1:N ^
* | |
* | +-------------------------------+
@@ -54,19 +74,19 @@
* | mode state changes
* v |
* +-----------------------------------------------------------------------+
- * | VcnInstance |
+ * | Vcn |
* | |
- * | Manages tunnel lifecycles based on fulfillable NetworkRequest(s) |
- * | and overall safe-mode |
+ * | Manages GatewayConnection lifecycles based on fulfillable |
+ * | NetworkRequest(s) and overall safe-mode |
* +-----------------------------------------------------------------------+
* | 1:N ^
* Creates to fulfill |
- * NetworkRequest(s), tears Notifies of VcnTunnel
+ * NetworkRequest(s), tears Notifies of VcnGatewayConnection
* down when no longer needed teardown (e.g. Network reaped)
* | and safe-mode timer changes
* v |
* +-----------------------------------------------------------------------+
- * | VcnTunnel |
+ * | VcnGatewayConnection |
* | |
* | Manages a single (IKEv2) tunnel session and NetworkAgent, |
* | handles mobility events, (IPsec) Tunnel setup and safe-mode timers |
@@ -92,20 +112,72 @@
public static final boolean VDBG = false; // STOPSHIP: if true
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ static final String VCN_CONFIG_FILE = "/data/system/vcn/configs.xml";
+
/* Binder context for this service */
@NonNull private final Context mContext;
@NonNull private final Dependencies mDeps;
@NonNull private final Looper mLooper;
+ @NonNull private final Handler mHandler;
@NonNull private final VcnNetworkProvider mNetworkProvider;
+ @GuardedBy("mLock")
+ @NonNull
+ private final Map<ParcelUuid, VcnConfig> mConfigs = new ArrayMap<>();
+
+ @NonNull private final Object mLock = new Object();
+
+ @NonNull private final PersistableBundleUtils.LockingReadWriteHelper mConfigDiskRwHelper;
+
@VisibleForTesting(visibility = Visibility.PRIVATE)
VcnManagementService(@NonNull Context context, @NonNull Dependencies deps) {
mContext = requireNonNull(context, "Missing context");
mDeps = requireNonNull(deps, "Missing dependencies");
mLooper = mDeps.getLooper();
+ mHandler = new Handler(mLooper);
mNetworkProvider = new VcnNetworkProvider(mContext, mLooper);
+
+ mConfigDiskRwHelper = mDeps.newPersistableBundleLockingReadWriteHelper(VCN_CONFIG_FILE);
+
+ // Run on handler to ensure I/O does not block system server startup
+ mHandler.post(() -> {
+ PersistableBundle configBundle = null;
+ try {
+ configBundle = mConfigDiskRwHelper.readFromDisk();
+ } catch (IOException e1) {
+ Slog.e(TAG, "Failed to read configs from disk; retrying", e1);
+
+ // Retry immediately. The IOException may have been transient.
+ try {
+ configBundle = mConfigDiskRwHelper.readFromDisk();
+ } catch (IOException e2) {
+ Slog.wtf(TAG, "Failed to read configs from disk", e2);
+ return;
+ }
+ }
+
+ if (configBundle != null) {
+ final Map<ParcelUuid, VcnConfig> configs =
+ PersistableBundleUtils.toMap(
+ configBundle,
+ PersistableBundleUtils::toParcelUuid,
+ VcnConfig::new);
+
+ synchronized (mLock) {
+ for (Entry<ParcelUuid, VcnConfig> entry : configs.entrySet()) {
+ // Ensure no new configs are overwritten; a carrier app may have added a new
+ // config.
+ if (!mConfigs.containsKey(entry.getKey())) {
+ mConfigs.put(entry.getKey(), entry.getValue());
+ }
+ }
+ // TODO: Trigger re-evaluation of active VCNs; start/stop VCNs as needed.
+ }
+ }
+ });
}
// Package-visibility for SystemServer to create instances.
@@ -130,16 +202,81 @@
}
return mHandlerThread.getLooper();
}
+
+ /**
+ * Retrieves the caller's UID
+ *
+ * <p>This call MUST be made before calling {@link Binder#clearCallingIdentity}, otherwise
+ * this will not work properly.
+ *
+ * @return
+ */
+ public int getBinderCallingUid() {
+ return Binder.getCallingUid();
+ }
+
+ /**
+ * Creates and returns a new {@link PersistableBundle.LockingReadWriteHelper}
+ *
+ * @param path the file path to read/write from/to.
+ * @return the {@link PersistableBundleUtils.LockingReadWriteHelper} instance
+ */
+ public PersistableBundleUtils.LockingReadWriteHelper
+ newPersistableBundleLockingReadWriteHelper(@NonNull String path) {
+ return new PersistableBundleUtils.LockingReadWriteHelper(path);
+ }
}
/** Notifies the VcnManagementService that external dependencies can be set up. */
public void systemReady() {
- // TODO: Retrieve existing profiles from KeyStore
-
mContext.getSystemService(ConnectivityManager.class)
.registerNetworkProvider(mNetworkProvider);
}
+ private void enforcePrimaryUser() {
+ final int uid = mDeps.getBinderCallingUid();
+ if (uid == Process.SYSTEM_UID) {
+ throw new IllegalStateException(
+ "Calling identity was System Server. Was Binder calling identity cleared?");
+ }
+
+ if (!UserHandle.getUserHandleForUid(uid).isSystem()) {
+ throw new SecurityException(
+ "VcnManagementService can only be used by callers running as the primary user");
+ }
+ }
+
+ private void enforceCallingUserAndCarrierPrivilege(ParcelUuid subscriptionGroup) {
+ // Only apps running in the primary (system) user are allowed to configure the VCN. This is
+ // in line with Telephony's behavior with regards to binding to a Carrier App provided
+ // CarrierConfigService.
+ enforcePrimaryUser();
+
+ // TODO (b/172619301): Check based on events propagated from CarrierPrivilegesTracker
+ final SubscriptionManager subMgr = mContext.getSystemService(SubscriptionManager.class);
+ final List<SubscriptionInfo> subscriptionInfos = new ArrayList<>();
+ Binder.withCleanCallingIdentity(
+ () -> {
+ subscriptionInfos.addAll(subMgr.getSubscriptionsInGroup(subscriptionGroup));
+ });
+
+ final TelephonyManager telMgr = mContext.getSystemService(TelephonyManager.class);
+ for (SubscriptionInfo info : subscriptionInfos) {
+ // Check subscription is active first; much cheaper/faster check, and an app (currently)
+ // cannot be carrier privileged for inactive subscriptions.
+ if (subMgr.isValidSlotIndex(info.getSimSlotIndex())
+ && telMgr.hasCarrierPrivileges(info.getSubscriptionId())) {
+ // TODO (b/173717728): Allow configuration for inactive, but manageable
+ // subscriptions.
+ // TODO (b/173718661): Check for whole subscription groups at a time.
+ return;
+ }
+ }
+
+ throw new SecurityException(
+ "Carrier privilege required for subscription group to set VCN Config");
+ }
+
/**
* Sets a VCN config for a given subscription group.
*
@@ -150,7 +287,17 @@
requireNonNull(subscriptionGroup, "subscriptionGroup was null");
requireNonNull(config, "config was null");
- // TODO: Store VCN configuration, trigger startup as necessary
+ enforceCallingUserAndCarrierPrivilege(subscriptionGroup);
+
+ synchronized (mLock) {
+ mConfigs.put(subscriptionGroup, config);
+
+ // Must be done synchronously to ensure that writes do not happen out-of-order.
+ writeConfigsToDiskLocked();
+ }
+
+ // TODO: Clear Binder calling identity
+ // TODO: Trigger startup as necessary
}
/**
@@ -162,7 +309,40 @@
public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup) {
requireNonNull(subscriptionGroup, "subscriptionGroup was null");
- // TODO: Clear VCN configuration, trigger teardown as necessary
+ enforceCallingUserAndCarrierPrivilege(subscriptionGroup);
+
+ synchronized (mLock) {
+ mConfigs.remove(subscriptionGroup);
+
+ // Must be done synchronously to ensure that writes do not happen out-of-order.
+ writeConfigsToDiskLocked();
+ }
+
+ // TODO: Clear Binder calling identity
+ // TODO: Trigger teardown as necessary
+ }
+
+ @GuardedBy("mLock")
+ private void writeConfigsToDiskLocked() {
+ try {
+ PersistableBundle bundle =
+ PersistableBundleUtils.fromMap(
+ mConfigs,
+ PersistableBundleUtils::fromParcelUuid,
+ VcnConfig::toPersistableBundle);
+ mConfigDiskRwHelper.writeToDisk(bundle);
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to save configs to disk", e);
+ throw new ServiceSpecificException(0, "Failed to save configs");
+ }
+ }
+
+ /** Get current configuration list for testing purposes */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ Map<ParcelUuid, VcnConfig> getConfigs() {
+ synchronized (mLock) {
+ return Collections.unmodifiableMap(mConfigs);
+ }
}
/**
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index a2b6304..5fde046 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -168,6 +168,7 @@
public static final int FGS_FEATURE_ALLOWED_BY_FGS_BINDING = 17;
public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE = 18;
public static final int FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD = 19;
+ public static final int FGS_FEATURE_ALLOWED_BY_EXEMPTED_PACKAGES = 20;
@IntDef(flag = true, prefix = { "FGS_FEATURE_" }, value = {
FGS_FEATURE_DENIED,
@@ -188,7 +189,8 @@
FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION,
FGS_FEATURE_ALLOWED_BY_FGS_BINDING,
FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE,
- FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD
+ FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD,
+ FGS_FEATURE_ALLOWED_BY_EXEMPTED_PACKAGES,
})
@Retention(RetentionPolicy.SOURCE)
public @interface FgsFeatureRetCode {}
@@ -275,6 +277,13 @@
static final long FGS_BG_START_RESTRICTION_CHANGE_ID = 170668199L;
/**
+ * If set to false for a package, the system will *not* exempt it from FGS-BG-start,
+ * even if it's in {#code ActiveServices.sFgsBgStartExemptedPackages}.
+ */
+ @ChangeId
+ static final long FGS_BG_START_USE_EXEMPTION_LIST_CHANGE_ID = 175801883;
+
+ /**
* If a service can not become foreground service due to BG-FGS-launch restriction or other
* reasons, throws an IllegalStateException.
*/
@@ -282,6 +291,25 @@
@EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S)
static final long FGS_START_EXCEPTION_CHANGE_ID = 174041399L;
+ /**
+ * Special allowlist that contains packages that are allowed to start FGS even if they target S,
+ * without using START_FOREGROUND_SERVICES_FROM_BACKGROUND.
+ *
+ * Note: we exempt FGS starts if either the "callee" or "caller" match any of the emempted
+ * packages. This means:
+ * - Exempted apps could call Context.startForegroundService() for services owned by any other
+ * apps.
+ * - Any apps could call Context.startForegroundService() for services owned by any exempted
+ * apps.
+ * And the call would succeed.
+ */
+ private static final ArraySet<String> sFgsBgStartExemptedPackages = new ArraySet<>();
+
+ static {
+ sFgsBgStartExemptedPackages.add("com.google.pixel.exo.bootstrapping"); //STOPSHIP Remove it.
+ sFgsBgStartExemptedPackages.add("com.android.chrome"); // STOPSHIP Remove it.
+ }
+
final Runnable mLastAnrDumpClearer = new Runnable() {
@Override public void run() {
synchronized (mAm) {
@@ -1672,13 +1700,12 @@
// TODO: remove as part of fixing b/173627642
@SuppressWarnings("AndroidFrameworkCompatChange")
private void postFgsNotificationLocked(ServiceRecord r) {
- final boolean isLegacyApp = (r.appInfo.targetSdkVersion < Build.VERSION_CODES.S);
boolean showNow = !mAm.mConstants.mFlagFgsNotificationDeferralEnabled;
if (!showNow) {
// Legacy apps' FGS notifications are not deferred unless the relevant
// DeviceConfig element has been set
showNow = mAm.mConstants.mFlagFgsNotificationDeferralApiGated
- && isLegacyApp;
+ && r.appInfo.targetSdkVersion < Build.VERSION_CODES.S;
}
if (!showNow) {
// is the notification such that it should show right away?
@@ -1733,11 +1760,6 @@
Slog.d(TAG_SERVICE, "FGS " + r
+ " notification in " + (when - now) + " ms");
}
- if (isLegacyApp) {
- Slog.i(TAG_SERVICE, "Deferring FGS notification in legacy app "
- + r.appInfo.packageName + "/" + UserHandle.formatUid(r.appInfo.uid)
- + " : " + r.foregroundNoti);
- }
mAm.mHandler.postAtTime(mPostDeferredFGSNotifications, when);
}
@@ -1761,7 +1783,7 @@
// The service might have been stopped or exited foreground state
// in the interval, so we lazy check whether we still need to show
// the notification.
- if (r.isForeground) {
+ if (r.isForeground && r.app != null) {
r.postNotification();
} else if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG_SERVICE, " - service no longer running/fg, ignoring");
@@ -5310,6 +5332,14 @@
}
}
+ // NOTE this should always be the last check.
+ if (ret == FGS_FEATURE_DENIED) {
+ if (isPackageExemptedFromFgsRestriction(r.appInfo.packageName, r.appInfo.uid)
+ || isPackageExemptedFromFgsRestriction(callingPackage, callingUid)) {
+ ret = FGS_FEATURE_ALLOWED_BY_EXEMPTED_PACKAGES;
+ }
+ }
+
final String debugInfo =
"[callingPackage: " + callingPackage
+ "; callingUid: " + callingUid
@@ -5327,6 +5357,13 @@
return ret;
}
+ private boolean isPackageExemptedFromFgsRestriction(String packageName, int uid) {
+ if (!sFgsBgStartExemptedPackages.contains(packageName)) {
+ return false;
+ }
+ return CompatChanges.isChangeEnabled(FGS_BG_START_USE_EXEMPTION_LIST_CHANGE_ID, uid);
+ }
+
private static String fgsCodeToString(@FgsFeatureRetCode int code) {
switch (code) {
case FGS_FEATURE_DENIED:
@@ -5367,6 +5404,8 @@
return "ALLOWED_BY_DEVICE_DEMO_MODE";
case FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD:
return "ALLOWED_BY_PROCESS_RECORD";
+ case FGS_FEATURE_ALLOWED_BY_EXEMPTED_PACKAGES:
+ return "FGS_FEATURE_ALLOWED_BY_EXEMPTED_PACKAGES";
default:
return "";
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 6892ef7..b0f296f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -370,9 +370,9 @@
volatile boolean mFlagFgsNotificationDeferralEnabled = true;
// Restrict FGS notification deferral policy to only those apps that target
- // API version S or higher. Disabled by default; set to "true" to force
- // legacy app FGS notifications to display immediately in all cases.
- volatile boolean mFlagFgsNotificationDeferralApiGated = false;
+ // API version S or higher. Enabled by default; set to "false" to defer FGS
+ // notifications from legacy apps as well.
+ volatile boolean mFlagFgsNotificationDeferralApiGated = true;
// Time in milliseconds to defer FGS notifications after their transition to
// the foreground state.
@@ -806,7 +806,7 @@
mFlagFgsNotificationDeferralApiGated = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
KEY_DEFERRED_FGS_NOTIFICATIONS_API_GATED,
- /*default value*/ false);
+ /*default value*/ true);
}
private void updateFgsNotificationDeferralInterval() {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7fb0bda..1841d67 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -11247,6 +11247,10 @@
// set on ION VMAs, therefore consider the entire ION heap as used kernel memory
kernelUsed += ionHeap;
}
+ final long gpuUsage = Debug.getGpuTotalUsageKb();
+ if (gpuUsage >= 0) {
+ pw.print(" GPU: "); pw.println(stringifyKBSize(gpuUsage));
+ }
final long lostRAM = memInfo.getTotalSizeKb()
- (ss[INDEX_TOTAL_PSS] - ss[INDEX_TOTAL_SWAP_PSS])
- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
@@ -12041,6 +12045,12 @@
// set on ION VMAs, therefore consider the entire ION heap as used kernel memory
kernelUsed += ionHeap;
}
+ final long gpuUsage = Debug.getGpuTotalUsageKb();
+ if (gpuUsage >= 0) {
+ memInfoBuilder.append(" GPU: ");
+ memInfoBuilder.append(stringifyKBSize(gpuUsage));
+ memInfoBuilder.append("\n");
+ }
memInfoBuilder.append(" Used RAM: ");
memInfoBuilder.append(stringifyKBSize(
totalPss - cachedPss + kernelUsed));
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 12fe3ed..fffa814 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2928,6 +2928,7 @@
final PlatformCompat platformCompat = (PlatformCompat)
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
String toggleValue = getNextArgRequired();
+ boolean killPackage = !"--no-kill".equals(getNextOption());
boolean toggleAll = false;
int targetSdkVersion = -1;
long changeId = -1;
@@ -2979,7 +2980,11 @@
CompatibilityChangeConfig overrides =
new CompatibilityChangeConfig(
new Compatibility.ChangeConfig(enabled, disabled));
- platformCompat.setOverrides(overrides, packageName);
+ if (killPackage) {
+ platformCompat.setOverrides(overrides, packageName);
+ } else {
+ platformCompat.setOverridesForTest(overrides, packageName);
+ }
pw.println("Enabled change " + changeId + " for " + packageName + ".");
}
return 0;
@@ -2998,13 +3003,21 @@
CompatibilityChangeConfig overrides =
new CompatibilityChangeConfig(
new Compatibility.ChangeConfig(enabled, disabled));
- platformCompat.setOverrides(overrides, packageName);
+ if (killPackage) {
+ platformCompat.setOverrides(overrides, packageName);
+ } else {
+ platformCompat.setOverridesForTest(overrides, packageName);
+ }
pw.println("Disabled change " + changeId + " for " + packageName + ".");
}
return 0;
case "reset":
if (toggleAll) {
- platformCompat.clearOverrides(packageName);
+ if (killPackage) {
+ platformCompat.clearOverrides(packageName);
+ } else {
+ platformCompat.clearOverridesForTest(packageName);
+ }
pw.println("Reset all changes for " + packageName + " to default value.");
return 0;
}
@@ -3410,15 +3423,18 @@
pw.println(" write");
pw.println(" Write all pending state to storage.");
pw.println(" compat [COMMAND] [...]: sub-commands for toggling app-compat changes.");
- pw.println(" enable|disable|reset <CHANGE_ID|CHANGE_NAME> <PACKAGE_NAME>");
+ pw.println(" enable|disable [--no-kill] <CHANGE_ID|CHANGE_NAME> <PACKAGE_NAME>");
+ pw.println(" Toggles a change either by id or by name for <PACKAGE_NAME>.");
+ pw.println(" It kills <PACKAGE_NAME> (to allow the toggle to take effect) unless --no-kill is provided.");
+ pw.println(" reset <CHANGE_ID|CHANGE_NAME> <PACKAGE_NAME>");
pw.println(" Toggles a change either by id or by name for <PACKAGE_NAME>.");
pw.println(" It kills <PACKAGE_NAME> (to allow the toggle to take effect).");
- pw.println(" enable-all|disable-all <targetSdkVersion> <PACKAGE_NAME");
+ pw.println(" enable-all|disable-all <targetSdkVersion> <PACKAGE_NAME>");
pw.println(" Toggles all changes that are gated by <targetSdkVersion>.");
- pw.println(" reset-all <PACKAGE_NAME>");
+ pw.println(" reset-all [--no-kill] <PACKAGE_NAME>");
pw.println(" Removes all existing overrides for all changes for ");
pw.println(" <PACKAGE_NAME> (back to default behaviour).");
- pw.println(" It kills <PACKAGE_NAME> (to allow the toggle to take effect).");
+ pw.println(" It kills <PACKAGE_NAME> (to allow the toggle to take effect) unless --no-kill is provided.");
pw.println(" memory-factor [command] [...]: sub-commands for overriding memory pressure factor");
pw.println(" set <NORMAL|MODERATE|LOW|CRITICAL>");
pw.println(" Overrides memory pressure factor. May also supply a raw int level");
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 82e9b46..2f7c523 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -254,9 +254,7 @@
mHandler = new Handler(mHandlerThread.getLooper());
// TODO(b/173077356): Replace directly calling the HAL with PowerStatsService queries
- // Make sure to init Hal Wrapper before creating BatteryStatsImpl.
- mPowerStatsHALWrapper = new PowerStatsHALWrapper.PowerStatsHALWrapperImpl();
- mPowerStatsHALWrapper.initialize();
+ mPowerStatsHALWrapper = PowerStatsHALWrapper.getPowerStatsHalImpl();
final MeasuredEnergyArray initialEnergies = getEnergyConsumptionData();
final boolean[] supportedBuckets = getSupportedEnergyBuckets(initialEnergies);
@@ -267,8 +265,6 @@
mStats.setRadioScanningTimeoutLocked(mContext.getResources().getInteger(
com.android.internal.R.integer.config_radioScanningTimeout) * 1000L);
mStats.setPowerProfileLocked(new PowerProfile(context));
- mStats.startTrackingSystemServerCpuTime();
-
mBatteryUsageStatsProvider = new BatteryUsageStatsProvider(context, mStats);
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 3b407f1..26f5c4c 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -16,6 +16,7 @@
package com.android.server.audio;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
@@ -31,14 +32,17 @@
import android.media.AudioSystem;
import android.media.IAudioRoutesObserver;
import android.media.ICapturePresetDevicesRoleDispatcher;
+import android.media.ICommunicationDeviceDispatcher;
import android.media.IStrategyPreferredDevicesDispatcher;
import android.media.MediaMetrics;
+import android.media.audiopolicy.AudioProductStrategy;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -49,6 +53,7 @@
import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
@@ -75,7 +80,8 @@
private final @NonNull Context mContext;
/** Forced device usage for communications sent to AudioSystem */
- private int mForcedUseForComm;
+ private AudioDeviceAttributes mPreferredDeviceforComm;
+ private int mCommunicationStrategyId = -1;
// Manages all connected devices, only ever accessed on the message loop
private final AudioDeviceInventory mDeviceInventory;
@@ -131,10 +137,23 @@
init();
}
+ private void initCommunicationStrategyId() {
+ List<AudioProductStrategy> strategies = AudioProductStrategy.getAudioProductStrategies();
+ for (AudioProductStrategy strategy : strategies) {
+ if (strategy.getAudioAttributesForLegacyStreamType(AudioSystem.STREAM_VOICE_CALL)
+ != null) {
+ mCommunicationStrategyId = strategy.getId();
+ return;
+ }
+ }
+ mCommunicationStrategyId = -1;
+ }
+
private void init() {
setupMessaging(mContext);
- mForcedUseForComm = AudioSystem.FORCE_NONE;
+ mPreferredDeviceforComm = null;
+ initCommunicationStrategyId();
}
/*package*/ Context getContext() {
@@ -219,8 +238,7 @@
synchronized (mDeviceStateLock) {
AudioDeviceAttributes device = null;
if (on) {
- device = new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_OUTPUT,
- AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, "");
+ device = new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, "");
} else {
CommunicationRouteClient client = getCommunicationRouteClientForPid(pid);
if (client == null || !client.requestsSpeakerphone()) {
@@ -233,6 +251,38 @@
}
}
+ /**
+ * Select device for use for communication use cases.
+ * @param cb Client binder for death detection
+ * @param pid Client pid
+ * @param device Device selected or null to unselect.
+ * @param eventSource for logging purposes
+ */
+ /*package*/ boolean setDeviceForCommunication(
+ IBinder cb, int pid, AudioDeviceInfo device, String eventSource) {
+
+ if (AudioService.DEBUG_COMM_RTE) {
+ Log.v(TAG, "setDeviceForCommunication, device: " + device + ", pid: " + pid);
+ }
+
+ synchronized (mSetModeLock) {
+ synchronized (mDeviceStateLock) {
+ AudioDeviceAttributes deviceAttr = null;
+ if (device != null) {
+ deviceAttr = new AudioDeviceAttributes(device);
+ } else {
+ CommunicationRouteClient client = getCommunicationRouteClientForPid(pid);
+ if (client == null) {
+ return false;
+ }
+ }
+ setCommunicationRouteForClient(
+ cb, pid, deviceAttr, BtHelper.SCO_MODE_UNDEFINED, eventSource);
+ }
+ }
+ return true;
+ }
+
@GuardedBy("mDeviceStateLock")
/*package*/ void setCommunicationRouteForClient(
IBinder cb, int pid, AudioDeviceAttributes device,
@@ -241,6 +291,10 @@
if (AudioService.DEBUG_COMM_RTE) {
Log.v(TAG, "setCommunicationRouteForClient: device: " + device);
}
+ AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
+ "setCommunicationRouteForClient for pid: " + pid
+ + " device: " + device
+ + " from API: " + eventSource)).printLog(TAG));
final boolean wasBtScoRequested = isBluetoothScoRequested();
final boolean wasSpeakerphoneRequested = isSpeakerphoneRequested();
@@ -278,6 +332,7 @@
} else {
removeCommunicationRouteClient(cb, true);
}
+ postBroadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
}
} else if (!isBtScoRequested && wasBtScoRequested) {
mBtHelper.stopBluetoothSco(eventSource);
@@ -325,6 +380,20 @@
}
/**
+ * Returns the device currently requested for communication use case.
+ * @return AudioDeviceInfo the requested device for communication.
+ */
+ AudioDeviceInfo getDeviceForCommunication() {
+ synchronized (mDeviceStateLock) {
+ AudioDeviceAttributes device = requestedCommunicationDevice();
+ if (device == null) {
+ return null;
+ }
+ return AudioManager.getDeviceInfoFromType(device.getType());
+ }
+ }
+
+ /**
* Helper method on top of requestedCommunicationDevice() indicating if
* speakerphone ON is currently requested or not.
* @return true if speakerphone ON requested, false otherwise.
@@ -344,7 +413,11 @@
* @return true if speakerphone is active, false otherwise.
*/
/*package*/ boolean isSpeakerphoneOn() {
- return getForcedUseForComm() == AudioSystem.FORCE_SPEAKER;
+ AudioDeviceAttributes device = getPreferredDeviceForComm();
+ if (device == null) {
+ return false;
+ }
+ return device.getInternalType() == AudioSystem.DEVICE_OUT_SPEAKER;
}
/**
@@ -511,7 +584,11 @@
* @return true if Bluetooth SCO is active , false otherwise.
*/
/*package*/ boolean isBluetoothScoOn() {
- return getForcedUseForComm() == AudioSystem.FORCE_BT_SCO;
+ AudioDeviceAttributes device = getPreferredDeviceForComm();
+ if (device == null) {
+ return false;
+ }
+ return AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(device.getInternalType());
}
/*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
@@ -563,14 +640,9 @@
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
- AudioDeviceAttributes device = new AudioDeviceAttributes(
- AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLUETOOTH_SCO, "");
+ AudioDeviceAttributes device =
+ new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, "");
setCommunicationRouteForClient(cb, pid, device, scoAudioMode, eventSource);
- if (!isBluetoothScoRequested()) {
- Log.w(TAG, "startBluetoothScoForClient_Sync: rejected for pid: "
- + pid + " mode owner pid: " + mModeOwnerPid);
- postBroadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
- }
}
}
}
@@ -599,10 +671,19 @@
return mDeviceInventory.setPreferredDevicesForStrategySync(strategy, devices);
}
+ /*package*/ void postSetPreferredDevicesForStrategy(int strategy,
+ @NonNull List<AudioDeviceAttributes> devices) {
+ sendILMsgNoDelay(MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY, SENDMSG_REPLACE, strategy, devices);
+ }
+
/*package*/ int removePreferredDevicesForStrategySync(int strategy) {
return mDeviceInventory.removePreferredDevicesForStrategySync(strategy);
}
+ /*package*/ void postRemovePreferredDevicesForStrategy(int strategy) {
+ sendIMsgNoDelay(MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY, SENDMSG_REPLACE, strategy);
+ }
+
/*package*/ void registerStrategyPreferredDevicesDispatcher(
@NonNull IStrategyPreferredDevicesDispatcher dispatcher) {
mDeviceInventory.registerStrategyPreferredDevicesDispatcher(dispatcher);
@@ -632,6 +713,45 @@
mDeviceInventory.unregisterCapturePresetDevicesRoleDispatcher(dispatcher);
}
+ /*package*/ void registerCommunicationDeviceDispatcher(
+ @NonNull ICommunicationDeviceDispatcher dispatcher) {
+ mCommDevDispatchers.register(dispatcher);
+ }
+
+ /*package*/ void unregisterCommunicationDeviceDispatcher(
+ @NonNull ICommunicationDeviceDispatcher dispatcher) {
+ mCommDevDispatchers.unregister(dispatcher);
+ }
+
+ // Monitoring of communication device
+ final RemoteCallbackList<ICommunicationDeviceDispatcher> mCommDevDispatchers =
+ new RemoteCallbackList<ICommunicationDeviceDispatcher>();
+
+ // portId of the device currently selected for communication: avoids broadcasting changes
+ // when same communication route is applied
+ @GuardedBy("mDeviceStateLock")
+ int mCurCommunicationPortId = -1;
+
+ @GuardedBy("mDeviceStateLock")
+ private void dispatchCommunicationDevice() {
+ AudioDeviceInfo device = getDeviceForCommunication();
+ int portId = (getDeviceForCommunication() == null) ? 0 : device.getId();
+ if (portId == mCurCommunicationPortId) {
+ return;
+ }
+ mCurCommunicationPortId = portId;
+
+ final int nbDispatchers = mCommDevDispatchers.beginBroadcast();
+ for (int i = 0; i < nbDispatchers; i++) {
+ try {
+ mCommDevDispatchers.getBroadcastItem(i)
+ .dispatchCommunicationDeviceChanged(portId);
+ } catch (RemoteException e) {
+ }
+ }
+ mCommDevDispatchers.finishBroadcast();
+ }
+
//---------------------------------------------------------------------
// Communication with (to) AudioService
//TODO check whether the AudioService methods are candidates to move here
@@ -888,9 +1008,12 @@
pw.println(" " + prefix + "pid: " + cl.getPid() + " device: "
+ cl.getDevice() + " cb: " + cl.getBinder()); });
- pw.println("\n" + prefix + "mForcedUseForComm: "
- + AudioSystem.forceUseConfigToString(mForcedUseForComm));
- pw.println(prefix + "mModeOwnerPid: " + mModeOwnerPid);
+ pw.println("\n" + prefix + "mPreferredDeviceforComm: "
+ + mPreferredDeviceforComm);
+ pw.println(prefix + "mCommunicationStrategyId: "
+ + mCommunicationStrategyId);
+
+ pw.println("\n" + prefix + "mModeOwnerPid: " + mModeOwnerPid);
mBtHelper.dump(pw, prefix);
}
@@ -985,6 +1108,7 @@
case MSG_RESTORE_DEVICES:
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
+ initCommunicationStrategyId();
mDeviceInventory.onRestoreDevices();
mBtHelper.onAudioServerDiedRestoreA2dp();
onUpdateCommunicationRoute("MSG_RESTORE_DEVICES");
@@ -1194,6 +1318,17 @@
final int strategy = msg.arg1;
mDeviceInventory.onSaveRemovePreferredDevices(strategy);
} break;
+ case MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY: {
+ final int strategy = msg.arg1;
+ final List<AudioDeviceAttributes> devices =
+ (List<AudioDeviceAttributes>) msg.obj;
+ setPreferredDevicesForStrategySync(strategy, devices);
+
+ } break;
+ case MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY: {
+ final int strategy = msg.arg1;
+ removePreferredDevicesForStrategySync(strategy);
+ } break;
case MSG_CHECK_MUTE_MUSIC:
checkMessagesMuteMusic(0);
break;
@@ -1286,7 +1421,8 @@
private static final int MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET = 38;
private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE = 39;
-
+ private static final int MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY = 40;
+ private static final int MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY = 41;
private static boolean isMessageHandledUnderWakelock(int msgId) {
switch(msgId) {
@@ -1526,16 +1662,25 @@
* @return selected forced usage for communication.
*/
@GuardedBy("mDeviceStateLock")
- private int getForcedUseForComm() {
+ @Nullable private AudioDeviceAttributes getPreferredDeviceForComm() {
boolean btSCoOn = mBluetoothScoOn && mBtHelper.isBluetoothScoOn();
-
if (btSCoOn) {
- return AudioSystem.FORCE_BT_SCO;
+ // Use the SCO device known to BtHelper so that it matches exactly
+ // what has been communicated to audio policy manager. The device
+ // returned by requestedCommunicationDevice() can be a dummy SCO device if legacy
+ // APIs are used to start SCO audio.
+ AudioDeviceAttributes device = mBtHelper.getHeadsetAudioDevice();
+ if (device != null) {
+ return device;
+ }
}
- if (isSpeakerphoneRequested()) {
- return AudioSystem.FORCE_SPEAKER;
+ AudioDeviceAttributes device = requestedCommunicationDevice();
+ if (device == null
+ || AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(device.getInternalType())) {
+ // Do not indicate BT SCO selection if SCO is requested but SCO is not ON
+ return null;
}
- return AudioSystem.FORCE_NONE;
+ return device;
}
/**
@@ -1545,32 +1690,27 @@
// @GuardedBy("mSetModeLock")
@GuardedBy("mDeviceStateLock")
private void onUpdateCommunicationRoute(String eventSource) {
- mForcedUseForComm = getForcedUseForComm();
-
+ mPreferredDeviceforComm = getPreferredDeviceForComm();
if (AudioService.DEBUG_COMM_RTE) {
- Log.v(TAG, "onUpdateCommunicationRoute, mForcedUseForComm: " + mForcedUseForComm
- + " eventSource: " + eventSource);
+ Log.v(TAG, "onUpdateCommunicationRoute, mPreferredDeviceforComm: "
+ + mPreferredDeviceforComm + " eventSource: " + eventSource);
}
- if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
- AudioSystem.setParameters("BT_SCO=on");
- setForceUse_Async(
- AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_BT_SCO, eventSource);
- setForceUse_Async(
- AudioSystem.FOR_RECORD, AudioSystem.FORCE_BT_SCO, eventSource);
- } else {
+ if (mPreferredDeviceforComm == null
+ || !AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(
+ mPreferredDeviceforComm.getInternalType())) {
AudioSystem.setParameters("BT_SCO=off");
- setForceUse_Async(
- AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, eventSource);
- if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) {
- setForceUse_Async(
- AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_SPEAKER, eventSource);
- } else {
- setForceUse_Async(
- AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE, eventSource);
- }
+ } else {
+ AudioSystem.setParameters("BT_SCO=on");
+ }
+ if (mPreferredDeviceforComm == null) {
+ postRemovePreferredDevicesForStrategy(mCommunicationStrategyId);
+ } else {
+ postSetPreferredDevicesForStrategy(
+ mCommunicationStrategyId, Arrays.asList(mPreferredDeviceforComm));
}
mAudioService.postUpdateRingerModeServiceInt();
+ dispatchCommunicationDevice();
}
private CommunicationRouteClient removeCommunicationRouteClient(
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 33a8a30..82586b8 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -648,6 +648,10 @@
/*package*/ int setPreferredDevicesForStrategySync(int strategy,
@NonNull List<AudioDeviceAttributes> devices) {
final long identity = Binder.clearCallingIdentity();
+
+ AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
+ "setPreferredDevicesForStrategySync, strategy: " + strategy
+ + " devices: " + devices)).printLog(TAG));
final int status = mAudioSystem.setDevicesRoleForStrategy(
strategy, AudioSystem.DEVICE_ROLE_PREFERRED, devices);
Binder.restoreCallingIdentity(identity);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index a04184c..ada67b1 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -85,6 +85,7 @@
import android.media.IAudioServerStateDispatcher;
import android.media.IAudioService;
import android.media.ICapturePresetDevicesRoleDispatcher;
+import android.media.ICommunicationDeviceDispatcher;
import android.media.IPlaybackConfigDispatcher;
import android.media.IRecordingConfigDispatcher;
import android.media.IRingtonePlayer;
@@ -4417,6 +4418,115 @@
restoreDeviceVolumeBehavior();
}
+ private static final int[] VALID_COMMUNICATION_DEVICE_TYPES = {
+ AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
+ AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
+ AudioDeviceInfo.TYPE_WIRED_HEADSET,
+ AudioDeviceInfo.TYPE_USB_HEADSET,
+ AudioDeviceInfo.TYPE_BUILTIN_EARPIECE,
+ AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
+ AudioDeviceInfo.TYPE_HEARING_AID,
+ AudioDeviceInfo.TYPE_BLE_HEADSET,
+ AudioDeviceInfo.TYPE_USB_DEVICE,
+ AudioDeviceInfo.TYPE_BLE_SPEAKER,
+ AudioDeviceInfo.TYPE_LINE_ANALOG,
+ AudioDeviceInfo.TYPE_HDMI,
+ AudioDeviceInfo.TYPE_AUX_LINE
+ };
+
+ private boolean isValidCommunicationDevice(AudioDeviceInfo device) {
+ for (int type : VALID_COMMUNICATION_DEVICE_TYPES) {
+ if (device.getType() == type) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** @see AudioManager#setDeviceForCommunication(int) */
+ public boolean setDeviceForCommunication(IBinder cb, int portId) {
+ final int uid = Binder.getCallingUid();
+ final int pid = Binder.getCallingPid();
+
+ AudioDeviceInfo device = null;
+ if (portId != 0) {
+ device = AudioManager.getDeviceForPortId(portId, AudioManager.GET_DEVICES_OUTPUTS);
+ if (device == null) {
+ throw new IllegalArgumentException("invalid portID " + portId);
+ }
+ if (!isValidCommunicationDevice(device)) {
+ throw new IllegalArgumentException("invalid device type " + device.getType());
+ }
+ }
+ final String eventSource = new StringBuilder("setDeviceForCommunication(")
+ .append(") from u/pid:").append(uid).append("/")
+ .append(pid).toString();
+
+ int deviceType = AudioSystem.DEVICE_OUT_DEFAULT;
+ String deviceAddress = null;
+ if (device != null) {
+ deviceType = device.getPort().type();
+ deviceAddress = device.getAddress();
+ } else {
+ AudioDeviceInfo curDevice = mDeviceBroker.getDeviceForCommunication();
+ if (curDevice != null) {
+ deviceType = curDevice.getPort().type();
+ deviceAddress = curDevice.getAddress();
+ }
+ }
+ // do not log metrics if clearing communication device while no communication device
+ // was selected
+ if (deviceType != AudioSystem.DEVICE_OUT_DEFAULT) {
+ new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE
+ + MediaMetrics.SEPARATOR + "setDeviceForCommunication")
+ .set(MediaMetrics.Property.DEVICE,
+ AudioSystem.getDeviceName(deviceType))
+ .set(MediaMetrics.Property.ADDRESS, deviceAddress)
+ .set(MediaMetrics.Property.STATE, device != null
+ ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED)
+ .record();
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ boolean status =
+ mDeviceBroker.setDeviceForCommunication(cb, pid, device, eventSource);
+ Binder.restoreCallingIdentity(ident);
+ return status;
+ }
+
+ /** @see AudioManager#getDeviceForCommunication() */
+ public int getDeviceForCommunication() {
+ final long ident = Binder.clearCallingIdentity();
+ AudioDeviceInfo device = mDeviceBroker.getDeviceForCommunication();
+ Binder.restoreCallingIdentity(ident);
+ if (device == null) {
+ return 0;
+ }
+ return device.getId();
+ }
+
+ /** @see AudioManager#addOnCommunicationDeviceChangedListener(
+ * Executor, AudioManager.OnCommunicationDeviceChangedListener)
+ */
+ public void registerCommunicationDeviceDispatcher(
+ @Nullable ICommunicationDeviceDispatcher dispatcher) {
+ if (dispatcher == null) {
+ return;
+ }
+ mDeviceBroker.registerCommunicationDeviceDispatcher(dispatcher);
+ }
+
+ /** @see AudioManager#removeOnCommunicationDeviceChangedListener(
+ * AudioManager.OnCommunicationDeviceChangedListener)
+ */
+ public void unregisterCommunicationDeviceDispatcher(
+ @Nullable ICommunicationDeviceDispatcher dispatcher) {
+ if (dispatcher == null) {
+ return;
+ }
+ mDeviceBroker.unregisterCommunicationDeviceDispatcher(dispatcher);
+ }
+
/** @see AudioManager#setSpeakerphoneOn(boolean) */
public void setSpeakerphoneOn(IBinder cb, boolean on) {
if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
@@ -5011,8 +5121,7 @@
switch (mPlatformType) {
case AudioSystem.PLATFORM_VOICE:
if (isInCommunication()) {
- if (mAudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
- == AudioSystem.FORCE_BT_SCO) {
+ if (mDeviceBroker.isBluetoothScoOn()) {
// Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
return AudioSystem.STREAM_BLUETOOTH_SCO;
} else {
@@ -5048,8 +5157,7 @@
}
default:
if (isInCommunication()) {
- if (mAudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
- == AudioSystem.FORCE_BT_SCO) {
+ if (mDeviceBroker.isBluetoothScoOn()) {
if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
return AudioSystem.STREAM_BLUETOOTH_SCO;
} else {
@@ -8798,14 +8906,8 @@
mPlaybackMonitor.playerAttributes(piid, attr, Binder.getCallingUid());
}
- /**
- * Update player event
- * @param piid Player id to update
- * @param event The new player event
- * @param deviceId The new player device id
- */
- public void playerEvent(int piid, int event, int deviceId) {
- mPlaybackMonitor.playerEvent(piid, event, deviceId, Binder.getCallingUid());
+ public void playerEvent(int piid, int event) {
+ mPlaybackMonitor.playerEvent(piid, event, Binder.getCallingUid());
}
public void playerHasOpPlayAudio(int piid, boolean hasOpPlayAudio) {
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index ae0e805..c57d5af 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -27,6 +27,7 @@
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothProfile;
import android.content.Intent;
+import android.media.AudioDeviceAttributes;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.os.Binder;
@@ -530,46 +531,64 @@
mDeviceBroker.postBroadcastScoConnectionState(state);
}
- private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive) {
- if (btDevice == null) {
- return true;
+ @Nullable AudioDeviceAttributes getHeadsetAudioDevice() {
+ if (mBluetoothHeadsetDevice == null) {
+ return null;
}
+ return btHeadsetDeviceToAudioDevice(mBluetoothHeadsetDevice);
+ }
+
+ private AudioDeviceAttributes btHeadsetDeviceToAudioDevice(BluetoothDevice btDevice) {
String address = btDevice.getAddress();
+ if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+ address = "";
+ }
BluetoothClass btClass = btDevice.getBluetoothClass();
- int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
- int[] outDeviceTypes = {
- AudioSystem.DEVICE_OUT_BLUETOOTH_SCO,
- AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
- AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT
- };
+ int nativeType = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
if (btClass != null) {
switch (btClass.getDeviceClass()) {
case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
- outDeviceTypes = new int[] { AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET };
+ nativeType = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
break;
case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
- outDeviceTypes = new int[] { AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT };
+ nativeType = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
break;
}
}
- if (!BluetoothAdapter.checkBluetoothAddress(address)) {
- address = "";
+ if (AudioService.DEBUG_DEVICES) {
+ Log.i(TAG, "btHeadsetDeviceToAudioDevice btDevice: " + btDevice
+ + " btClass: " + (btClass == null ? "Unknown" : btClass)
+ + " nativeType: " + nativeType + " address: " + address);
}
+ return new AudioDeviceAttributes(nativeType, address);
+ }
+
+ private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive) {
+ if (btDevice == null) {
+ return true;
+ }
+ int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ AudioDeviceAttributes audioDevice = btHeadsetDeviceToAudioDevice(btDevice);
String btDeviceName = getName(btDevice);
boolean result = false;
if (isActive) {
- result |= mDeviceBroker.handleDeviceConnection(
- isActive, outDeviceTypes[0], address, btDeviceName);
+ result |= mDeviceBroker.handleDeviceConnection(isActive, audioDevice.getInternalType(),
+ audioDevice.getAddress(), btDeviceName);
} else {
+ int[] outDeviceTypes = {
+ AudioSystem.DEVICE_OUT_BLUETOOTH_SCO,
+ AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
+ AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT
+ };
for (int outDeviceType : outDeviceTypes) {
result |= mDeviceBroker.handleDeviceConnection(
- isActive, outDeviceType, address, btDeviceName);
+ isActive, outDeviceType, audioDevice.getAddress(), btDeviceName);
}
}
// handleDeviceConnection() && result to make sure the method get executed
result = mDeviceBroker.handleDeviceConnection(
- isActive, inDevice, address, btDeviceName) && result;
+ isActive, inDevice, audioDevice.getAddress(), btDeviceName) && result;
return result;
}
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 36c67cd..a577883 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -233,25 +233,15 @@
}
}
- /**
- * Update player event
- * @param piid Player id to update
- * @param event The new player event
- * @param deviceId The new player device id
- * @param binderUid Calling binder uid
- */
- public void playerEvent(int piid, int event, int deviceId, int binderUid) {
- if (DEBUG) {
- Log.v(TAG, String.format("playerEvent(piid=%d, deviceId=%d, event=%d)",
- piid, deviceId, event));
- }
+ public void playerEvent(int piid, int event, int binderUid) {
+ if (DEBUG) { Log.v(TAG, String.format("playerEvent(piid=%d, event=%d)", piid, event)); }
final boolean change;
synchronized(mPlayerLock) {
final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
if (apc == null) {
return;
}
- sEventLogger.log(new PlayerEvent(piid, event, deviceId));
+ sEventLogger.log(new PlayerEvent(piid, event));
if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
for (Integer uidInteger: mBannedUids) {
if (checkBanPlayer(apc, uidInteger.intValue())) {
@@ -269,7 +259,7 @@
if (checkConfigurationCaller(piid, apc, binderUid)) {
//TODO add generation counter to only update to the latest state
checkVolumeForPrivilegedAlarm(apc, event);
- change = apc.handleStateEvent(event, deviceId);
+ change = apc.handleStateEvent(event);
} else {
Log.e(TAG, "Error handling event " + event);
change = false;
@@ -299,8 +289,7 @@
mPlayers.remove(new Integer(piid));
mDuckingManager.removeReleased(apc);
checkVolumeForPrivilegedAlarm(apc, AudioPlaybackConfiguration.PLAYER_STATE_RELEASED);
- change = apc.handleStateEvent(AudioPlaybackConfiguration.PLAYER_STATE_RELEASED,
- AudioPlaybackConfiguration.PLAYER_DEVICEID_INVALID);
+ change = apc.handleStateEvent(AudioPlaybackConfiguration.PLAYER_STATE_RELEASED);
}
}
if (change) {
@@ -879,19 +868,16 @@
// only keeping the player interface ID as it uniquely identifies the player in the event
final int mPlayerIId;
final int mState;
- final int mDeviceId;
- PlayerEvent(int piid, int state, int deviceId) {
+ PlayerEvent(int piid, int state) {
mPlayerIId = piid;
mState = state;
- mDeviceId = deviceId;
}
@Override
public String eventToString() {
return new StringBuilder("player piid:").append(mPlayerIId).append(" state:")
- .append(AudioPlaybackConfiguration.toLogFriendlyPlayerState(mState))
- .append(" DeviceId:").append(mDeviceId).toString();
+ .append(AudioPlaybackConfiguration.toLogFriendlyPlayerState(mState)).toString();
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java
index 78e875b..a26662d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java
@@ -133,7 +133,7 @@
if (tagName.equals(TAG_FACE)) {
String name = parser.getAttributeValue(null, ATTR_NAME);
int faceId = parser.getAttributeInt(null, ATTR_FACE_ID);
- int deviceId = parser.getAttributeInt(null, ATTR_DEVICE_ID);
+ long deviceId = parser.getAttributeLong(null, ATTR_DEVICE_ID);
mBiometrics.add(new Face(name, faceId, deviceId));
}
}
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index ff31931..a8aa9aa 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -143,6 +143,9 @@
* @return {@code true} if the change should be enabled for the package.
*/
boolean isEnabled(ApplicationInfo app) {
+ if (app == null) {
+ return defaultValue();
+ }
if (mPackageOverrides != null && mPackageOverrides.containsKey(app.packageName)) {
return mPackageOverrides.get(app.packageName);
}
@@ -156,6 +159,15 @@
}
/**
+ * Returns the default value for the change id, assuming there are no overrides.
+ *
+ * @return {@code false} if it's a default disabled change, {@code true} otherwise.
+ */
+ boolean defaultValue() {
+ return !getDisabled();
+ }
+
+ /**
* Checks whether a change has an override for a package.
* @param packageName name of the package
* @return true if there is such override
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index d80c58b..8511118 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -392,6 +392,14 @@
return alreadyKnown;
}
+ boolean defaultChangeIdValue(long changeId) {
+ CompatChange c = mChanges.get(changeId);
+ if (c == null) {
+ return true;
+ }
+ return c.defaultValue();
+ }
+
@VisibleForTesting
void clearChanges() {
synchronized (mChanges) {
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 77d5411..aa85f7f 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -60,7 +60,6 @@
private final CompatConfig mCompatConfig;
private static int sMinTargetSdk = Build.VERSION_CODES.Q;
- private static int sMaxTargetSdk = Build.VERSION_CODES.R;
public PlatformCompat(Context context) {
mContext = context;
@@ -120,10 +119,12 @@
* permission check.
*/
public boolean isChangeEnabledInternal(long changeId, ApplicationInfo appInfo) {
- boolean value = isChangeEnabledInternalNoLogging(changeId, appInfo);
- reportChange(changeId, appInfo.uid,
- value ? ChangeReporter.STATE_ENABLED : ChangeReporter.STATE_DISABLED);
- return value;
+ boolean enabled = isChangeEnabledInternalNoLogging(changeId, appInfo);
+ if (appInfo != null) {
+ reportChange(changeId, appInfo.uid,
+ enabled ? ChangeReporter.STATE_ENABLED : ChangeReporter.STATE_DISABLED);
+ }
+ return enabled;
}
@Override
@@ -131,9 +132,6 @@
@UserIdInt int userId) {
checkCompatChangeReadAndLogPermission();
ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
- if (appInfo == null) {
- return true;
- }
return isChangeEnabled(changeId, appInfo);
}
@@ -142,7 +140,7 @@
checkCompatChangeReadAndLogPermission();
String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
if (packages == null || packages.length == 0) {
- return true;
+ return mCompatConfig.defaultChangeIdValue(changeId);
}
boolean enabled = true;
for (String packageName : packages) {
@@ -385,8 +383,7 @@
return false;
}
if (change.getEnableSinceTargetSdk() > 0) {
- if (change.getEnableSinceTargetSdk() < sMinTargetSdk
- || change.getEnableSinceTargetSdk() > sMaxTargetSdk) {
+ if (change.getEnableSinceTargetSdk() < sMinTargetSdk) {
return false;
}
}
diff --git a/services/core/java/com/android/server/display/AmbientBrightnessStatsTracker.java b/services/core/java/com/android/server/display/AmbientBrightnessStatsTracker.java
index 0f1e666..d74c702 100644
--- a/services/core/java/com/android/server/display/AmbientBrightnessStatsTracker.java
+++ b/services/core/java/com/android/server/display/AmbientBrightnessStatsTracker.java
@@ -217,7 +217,6 @@
}
final LocalDate cutOffDate = mInjector.getLocalDate().minusDays(MAX_DAYS_TO_TRACK);
- parser.next();
int outerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index 7a8ba9f..2375f74 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -622,7 +622,6 @@
final long timeCutOff = mInjector.currentTimeMillis() - MAX_EVENT_AGE;
- parser.next();
int outerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index 92a3ccf..727944d 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -77,7 +77,6 @@
import com.android.server.DisplayThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;
@@ -119,6 +118,7 @@
private static final int MSG_APPLY_NIGHT_DISPLAY_ANIMATED = 3;
private static final int MSG_APPLY_GLOBAL_SATURATION = 4;
private static final int MSG_APPLY_DISPLAY_WHITE_BALANCE = 5;
+ private static final int MSG_APPLY_REDUCE_BRIGHT_COLORS = 6;
/**
* Return value if a setting has not been set.
@@ -129,17 +129,6 @@
* Evaluator used to animate color matrix transitions.
*/
private static final ColorMatrixEvaluator COLOR_MATRIX_EVALUATOR = new ColorMatrixEvaluator();
-
- private final NightDisplayTintController mNightDisplayTintController =
- new NightDisplayTintController();
-
- @VisibleForTesting
- final DisplayWhiteBalanceTintController mDisplayWhiteBalanceTintController =
- new DisplayWhiteBalanceTintController();
-
- private final TintController mGlobalSaturationTintController =
- new GlobalSaturationTintController();
-
/**
* Matrix and offset used for converting color to grayscale.
*/
@@ -163,6 +152,16 @@
1f, 1f, 1f, 1f
};
+ @VisibleForTesting
+ final DisplayWhiteBalanceTintController mDisplayWhiteBalanceTintController =
+ new DisplayWhiteBalanceTintController();
+ private final NightDisplayTintController mNightDisplayTintController =
+ new NightDisplayTintController();
+ private final TintController mGlobalSaturationTintController =
+ new GlobalSaturationTintController();
+ private final ReduceBrightColorsTintController mReduceBrightColorsTintController =
+ new ReduceBrightColorsTintController();
+
private final Handler mHandler;
private final AppSaturationController mAppSaturationController = new AppSaturationController();
@@ -354,6 +353,14 @@
case Secure.DISPLAY_WHITE_BALANCE_ENABLED:
updateDisplayWhiteBalanceStatus();
break;
+ case Secure.REDUCE_BRIGHT_COLORS_ACTIVATED:
+ onReduceBrightColorsActivationChanged();
+ mHandler.sendEmptyMessage(MSG_APPLY_REDUCE_BRIGHT_COLORS);
+ break;
+ case Secure.REDUCE_BRIGHT_COLORS_LEVEL:
+ onReduceBrightColorsStrengthLevelChanged();
+ mHandler.sendEmptyMessage(MSG_APPLY_REDUCE_BRIGHT_COLORS);
+ break;
}
}
}
@@ -372,17 +379,19 @@
false /* notifyForDescendants */, mContentObserver, mCurrentUser);
cr.registerContentObserver(System.getUriFor(System.DISPLAY_COLOR_MODE),
false /* notifyForDescendants */, mContentObserver, mCurrentUser);
- cr.registerContentObserver(
- Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED),
+ cr.registerContentObserver(Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED),
false /* notifyForDescendants */, mContentObserver, mCurrentUser);
cr.registerContentObserver(
Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED),
false /* notifyForDescendants */, mContentObserver, mCurrentUser);
- cr.registerContentObserver(
- Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER),
+ cr.registerContentObserver(Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER),
false /* notifyForDescendants */, mContentObserver, mCurrentUser);
cr.registerContentObserver(Secure.getUriFor(Secure.DISPLAY_WHITE_BALANCE_ENABLED),
false /* notifyForDescendants */, mContentObserver, mCurrentUser);
+ cr.registerContentObserver(Secure.getUriFor(Secure.REDUCE_BRIGHT_COLORS_ACTIVATED),
+ false /* notifyForDescendants */, mContentObserver, mCurrentUser);
+ cr.registerContentObserver(Secure.getUriFor(Secure.REDUCE_BRIGHT_COLORS_LEVEL),
+ false /* notifyForDescendants */, mContentObserver, mCurrentUser);
// Apply the accessibility settings first, since they override most other settings.
onAccessibilityInversionChanged();
@@ -420,6 +429,17 @@
updateDisplayWhiteBalanceStatus();
}
+
+ if (mReduceBrightColorsTintController.isAvailable(getContext())) {
+ mReduceBrightColorsTintController
+ .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix());
+ onReduceBrightColorsStrengthLevelChanged();
+ final boolean reset = resetReduceBrightColors();
+ if (!reset) {
+ onReduceBrightColorsActivationChanged();
+ mHandler.sendEmptyMessage(MSG_APPLY_REDUCE_BRIGHT_COLORS);
+ }
+ }
}
private void tearDown() {
@@ -444,6 +464,27 @@
if (mGlobalSaturationTintController.isAvailable(getContext())) {
mGlobalSaturationTintController.setActivated(null);
}
+
+ if (mReduceBrightColorsTintController.isAvailable(getContext())) {
+ mReduceBrightColorsTintController.setActivated(null);
+ }
+ }
+
+ private boolean resetReduceBrightColors() {
+ if (mCurrentUser == UserHandle.USER_NULL) {
+ return false;
+ }
+
+ final boolean isSettingActivated = Secure.getIntForUser(getContext().getContentResolver(),
+ Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 0, mCurrentUser) == 1;
+ final boolean shouldResetOnReboot = Secure.getIntForUser(getContext().getContentResolver(),
+ Secure.REDUCE_BRIGHT_COLORS_PERSIST_ACROSS_REBOOTS, 0, mCurrentUser) == 0;
+ if (isSettingActivated && mReduceBrightColorsTintController.isActivatedStateNotSet()
+ && shouldResetOnReboot) {
+ return Secure.putIntForUser(getContext().getContentResolver(),
+ Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 0, mCurrentUser);
+ }
+ return false;
}
private void onNightDisplayAutoModeChanged(int autoMode) {
@@ -572,6 +613,24 @@
isAccessiblityInversionEnabled() ? MATRIX_INVERT_COLOR : null);
}
+ private void onReduceBrightColorsActivationChanged() {
+ if (mCurrentUser == UserHandle.USER_NULL) {
+ return;
+ }
+ mReduceBrightColorsTintController.setActivated(
+ Secure.getIntForUser(getContext().getContentResolver(),
+ Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 0, mCurrentUser) == 1);
+ }
+
+ private void onReduceBrightColorsStrengthLevelChanged() {
+ if (mCurrentUser == UserHandle.USER_NULL) {
+ return;
+ }
+ mReduceBrightColorsTintController.setMatrix(
+ Secure.getIntForUser(getContext().getContentResolver(),
+ Secure.REDUCE_BRIGHT_COLORS_LEVEL, 0, mCurrentUser));
+ }
+
/**
* Applies current color temperature matrix, or removes it if deactivated.
*
@@ -937,6 +996,14 @@
pw.println(" Not available");
}
+ pw.println("Reduce bright colors:");
+ if (mReduceBrightColorsTintController.isAvailable(getContext())) {
+ pw.println(" Activated: " + mReduceBrightColorsTintController.isActivated());
+ mReduceBrightColorsTintController.dump(pw);
+ } else {
+ pw.println(" Not available");
+ }
+
pw.println("Color mode: " + getColorModeInternal());
}
@@ -1438,6 +1505,9 @@
mGlobalSaturationTintController.setMatrix(msg.arg1);
applyTint(mGlobalSaturationTintController, false);
break;
+ case MSG_APPLY_REDUCE_BRIGHT_COLORS:
+ applyTint(mReduceBrightColorsTintController, true);
+ break;
case MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE:
applyTint(mNightDisplayTintController, true);
break;
diff --git a/services/core/java/com/android/server/display/color/DisplayTransformManager.java b/services/core/java/com/android/server/display/color/DisplayTransformManager.java
index 3b0069c..5c68c51 100644
--- a/services/core/java/com/android/server/display/color/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/color/DisplayTransformManager.java
@@ -59,6 +59,10 @@
*/
public static final int LEVEL_COLOR_MATRIX_GRAYSCALE = 200;
/**
+ * Color transform level used by A11y services to reduce bright colors.
+ */
+ public static final int LEVEL_COLOR_MATRIX_REDUCE_BRIGHT_COLORS = 250;
+ /**
* Color transform level used by A11y services to invert the display colors.
*/
public static final int LEVEL_COLOR_MATRIX_INVERT_COLOR = 300;
@@ -97,7 +101,7 @@
* Map of level -> color transformation matrix.
*/
@GuardedBy("mColorMatrix")
- private final SparseArray<float[]> mColorMatrix = new SparseArray<>(5);
+ private final SparseArray<float[]> mColorMatrix = new SparseArray<>(6);
/**
* Temporary matrix used internally by {@link #computeColorMatrixLocked()}.
*/
diff --git a/services/core/java/com/android/server/display/color/ReduceBrightColorsTintController.java b/services/core/java/com/android/server/display/color/ReduceBrightColorsTintController.java
new file mode 100644
index 0000000..7e120c9
--- /dev/null
+++ b/services/core/java/com/android/server/display/color/ReduceBrightColorsTintController.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.color;
+
+import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_REDUCE_BRIGHT_COLORS;
+
+import android.content.Context;
+import android.hardware.display.ColorDisplayManager;
+import android.opengl.Matrix;
+import android.util.Slog;
+
+import com.android.internal.R;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+
+/**
+ * Control the color transform for bright color reduction.
+ */
+public class ReduceBrightColorsTintController extends TintController {
+
+ private final float[] mMatrix = new float[16];
+ private final float[] mCoefficients = new float[9];
+
+ private int mStrength;
+
+ @Override
+ public void setUp(Context context, boolean needsLinear) {
+ final String[] coefficients = context.getResources().getStringArray(
+ needsLinear ? R.array.config_reduceBrightColorsCoefficients
+ : R.array.config_reduceBrightColorsCoefficientsNative);
+ for (int i = 0; i < 9 && i < coefficients.length; i++) {
+ mCoefficients[i] = Float.parseFloat(coefficients[i]);
+ }
+ }
+
+ @Override
+ public float[] getMatrix() {
+ return isActivated() ? Arrays.copyOf(mMatrix, mMatrix.length)
+ : ColorDisplayService.MATRIX_IDENTITY;
+ }
+
+ @Override
+ public void setMatrix(int strengthLevel) {
+ // Clamp to valid range.
+ if (strengthLevel < 0) {
+ strengthLevel = 0;
+ } else if (strengthLevel > 100) {
+ strengthLevel = 100;
+ }
+ Slog.d(ColorDisplayService.TAG, "Setting bright color reduction level: " + strengthLevel);
+ mStrength = strengthLevel;
+
+ Matrix.setIdentityM(mMatrix, 0);
+
+ final float percentageStrength = strengthLevel / 100f;
+ final float squaredPercentageStrength = percentageStrength * percentageStrength;
+ final float red =
+ squaredPercentageStrength * mCoefficients[0] + percentageStrength * mCoefficients[1]
+ + mCoefficients[2];
+ final float green =
+ squaredPercentageStrength * mCoefficients[3] + percentageStrength * mCoefficients[4]
+ + mCoefficients[5];
+ final float blue =
+ squaredPercentageStrength * mCoefficients[6] + percentageStrength * mCoefficients[7]
+ + mCoefficients[8];
+ mMatrix[0] = clamp(red);
+ mMatrix[5] = clamp(green);
+ mMatrix[10] = clamp(blue);
+ }
+
+ private float clamp(float value) {
+ if (value > 1f) {
+ return 1f;
+ } else if (value < 0f) {
+ return 0f;
+ }
+ return value;
+ }
+
+ @Override
+ public void dump(PrintWriter pw) {
+ pw.println(" mStrength = " + mStrength);
+ }
+
+ @Override
+ public int getLevel() {
+ return LEVEL_COLOR_MATRIX_REDUCE_BRIGHT_COLORS;
+ }
+
+ @Override
+ public boolean isAvailable(Context context) {
+ return ColorDisplayManager.isColorTransformAccelerated(context);
+ }
+
+ public int getStrength() {
+ return mStrength;
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 8a753c5..c15fdca 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1655,6 +1655,12 @@
}
@Override
+ public boolean shouldHandleTvPowerKey() {
+ enforceAccessPermission();
+ return HdmiControlService.this.shouldHandleTvPowerKey();
+ }
+
+ @Override
public void queryDisplayStatus(final IHdmiControlCallback callback) {
enforceAccessPermission();
runOnServiceThread(new Runnable() {
@@ -2346,6 +2352,24 @@
source.toggleAndFollowTvPower();
}
+ @VisibleForTesting
+ protected boolean shouldHandleTvPowerKey() {
+ if (isTvDevice()) {
+ return false;
+ }
+ String powerControlMode = getHdmiCecConfig().getStringValue(
+ HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE);
+ if (powerControlMode.equals(HdmiControlManager.POWER_CONTROL_MODE_NONE)) {
+ return false;
+ }
+ int hdmiCecEnabled = getHdmiCecConfig().getIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED);
+ if (hdmiCecEnabled != HdmiControlManager.HDMI_CEC_CONTROL_ENABLED) {
+ return false;
+ }
+ return true;
+ }
+
@ServiceThreadOnly
protected void queryDisplayStatus(final IHdmiControlCallback callback) {
assertRunOnServiceThread();
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index bfc751f..bff81e6 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -41,11 +41,13 @@
import android.hardware.display.DisplayViewport;
import android.hardware.input.IInputDevicesChangedListener;
import android.hardware.input.IInputManager;
+import android.hardware.input.IInputSensorEventListener;
import android.hardware.input.ITabletModeChangedListener;
import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.InputManager;
import android.hardware.input.InputManagerInternal;
import android.hardware.input.InputManagerInternal.LidSwitchCallback;
+import android.hardware.input.InputSensorInfo;
import android.hardware.input.KeyboardLayout;
import android.hardware.input.TouchCalibration;
import android.media.AudioManager;
@@ -117,6 +119,7 @@
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -158,9 +161,6 @@
"com.snapchat.android" // b/173297887
};
- /** TODO(b/169067926): Remove this. */
- private static final boolean UNTRUSTED_TOUCHES_TOAST = false;
-
// Pointer to native input manager service object.
private final long mPtr;
@@ -184,12 +184,24 @@
private final List<TabletModeChangedListenerRecord> mTempTabletModeChangedListenersToNotify =
new ArrayList<>();
+ private final Object mSensorEventLock = new Object();
+ // List of currently registered sensor event listeners by process id
+ @GuardedBy("mSensorEventLock")
+ private final SparseArray<SensorEventListenerRecord> mSensorEventListeners =
+ new SparseArray<>();
+ private final List<SensorEventListenerRecord> mSensorEventListenersToNotify =
+ new ArrayList<>();
+ private final List<SensorEventListenerRecord> mSensorAccuracyListenersToNotify =
+ new ArrayList<>();
+
// Persistent data store. Must be locked each time during use.
private final PersistentDataStore mDataStore = new PersistentDataStore();
// List of currently registered input devices changed listeners by process id.
private Object mInputDevicesLock = new Object();
+ @GuardedBy("mInputDevicesLock")
private boolean mInputDevicesChangedPending; // guarded by mInputDevicesLock
+ @GuardedBy("mInputDevicesLock")
private InputDevice[] mInputDevices = new InputDevice[0];
private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners =
new SparseArray<InputDevicesChangedListenerRecord>(); // guarded by mInputDevicesLock
@@ -247,7 +259,7 @@
int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists);
private static native InputChannel nativeCreateInputChannel(long ptr, String name);
private static native InputChannel nativeCreateInputMonitor(long ptr, int displayId,
- boolean isGestureMonitor, String name);
+ boolean isGestureMonitor, String name, int pid);
private static native void nativeRemoveInputChannel(long ptr, IBinder connectionToken);
private static native void nativePilferPointers(long ptr, IBinder token);
private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
@@ -293,6 +305,11 @@
private static native boolean nativeCanDispatchToDisplay(long ptr, int deviceId, int displayId);
private static native void nativeNotifyPortAssociationsChanged(long ptr);
private static native void nativeSetMotionClassifierEnabled(long ptr, boolean enabled);
+ private static native InputSensorInfo[] nativeGetSensorList(long ptr, int deviceId);
+ private static native boolean nativeFlushSensor(long ptr, int deviceId, int sensorType);
+ private static native boolean nativeEnableSensor(long ptr, int deviceId, int sensorType,
+ int samplingPeriodUs, int maxBatchReportLatencyUs);
+ private static native void nativeDisableSensor(long ptr, int deviceId, int sensorType);
// Maximum number of milliseconds to wait for input event injection.
private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
@@ -590,7 +607,7 @@
}
return nativeCreateInputMonitor(mPtr, displayId, false /* isGestureMonitor */,
- inputChannelName);
+ inputChannelName, Binder.getCallingPid());
}
/**
@@ -618,7 +635,7 @@
final long ident = Binder.clearCallingIdentity();
try {
InputChannel inputChannel = nativeCreateInputMonitor(
- mPtr, displayId, true /*isGestureMonitor*/, inputChannelName);
+ mPtr, displayId, true /*isGestureMonitor*/, inputChannelName, pid);
InputMonitorHost host = new InputMonitorHost(inputChannel.getToken());
synchronized (mGestureMonitorPidsLock) {
mGestureMonitorPidsByToken.put(inputChannel.getToken(), pid);
@@ -2047,6 +2064,97 @@
nativeNotifyPortAssociationsChanged(mPtr);
}
+ @Override // Binder call
+ public InputSensorInfo[] getSensorList(int deviceId) {
+ InputSensorInfo[] sensors = nativeGetSensorList(mPtr, deviceId);
+ return sensors;
+ }
+
+ @Override // Binder call
+ public boolean registerSensorListener(IInputSensorEventListener listener) {
+ if (DEBUG) {
+ Slog.d(TAG, "registerSensorListener: listener=" + listener + " callingPid="
+ + Binder.getCallingPid());
+ }
+ if (listener == null) {
+ Slog.e(TAG, "listener must not be null");
+ return false;
+ }
+
+ synchronized (mInputDevicesLock) {
+ int callingPid = Binder.getCallingPid();
+ if (mSensorEventListeners.get(callingPid) != null) {
+ Slog.e(TAG, "The calling process " + callingPid + " has already "
+ + "registered an InputSensorEventListener.");
+ return false;
+ }
+
+ SensorEventListenerRecord record =
+ new SensorEventListenerRecord(callingPid, listener);
+ try {
+ IBinder binder = listener.asBinder();
+ binder.linkToDeath(record, 0);
+ } catch (RemoteException ex) {
+ // give up
+ throw new RuntimeException(ex);
+ }
+
+ mSensorEventListeners.put(callingPid, record);
+ }
+ return true;
+ }
+
+ @Override // Binder call
+ public void unregisterSensorListener(IInputSensorEventListener listener) {
+ if (DEBUG) {
+ Slog.d(TAG, "unregisterSensorListener: listener=" + listener + " callingPid="
+ + Binder.getCallingPid());
+ }
+
+ if (listener == null) {
+ throw new IllegalArgumentException("listener must not be null");
+ }
+
+ synchronized (mInputDevicesLock) {
+ int callingPid = Binder.getCallingPid();
+ if (mSensorEventListeners.get(callingPid) != null) {
+ SensorEventListenerRecord record = mSensorEventListeners.get(callingPid);
+ if (record.getListener().asBinder() != listener.asBinder()) {
+ throw new IllegalArgumentException("listener is not registered");
+ }
+ mSensorEventListeners.remove(callingPid);
+ }
+ }
+ }
+
+ @Override // Binder call
+ public boolean flushSensor(int deviceId, int sensorType) {
+ synchronized (mInputDevicesLock) {
+ int callingPid = Binder.getCallingPid();
+ SensorEventListenerRecord listener = mSensorEventListeners.get(callingPid);
+ if (listener != null) {
+ return nativeFlushSensor(mPtr, deviceId, sensorType);
+ }
+ return false;
+ }
+ }
+
+ @Override // Binder call
+ public boolean enableSensor(int deviceId, int sensorType, int samplingPeriodUs,
+ int maxBatchReportLatencyUs) {
+ synchronized (mInputDevicesLock) {
+ return nativeEnableSensor(mPtr, deviceId, sensorType, samplingPeriodUs,
+ maxBatchReportLatencyUs);
+ }
+ }
+
+ @Override // Binder call
+ public void disableSensor(int deviceId, int sensorType) {
+ synchronized (mInputDevicesLock) {
+ nativeDisableSensor(mPtr, deviceId, sensorType);
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
@@ -2199,8 +2307,7 @@
// Native callback
private void notifyUntrustedTouch(String packageName) {
// TODO(b/169067926): Remove toast after gathering feedback on dogfood.
- if (!UNTRUSTED_TOUCHES_TOAST || ArrayUtils.contains(
- PACKAGE_BLOCKLIST_FOR_UNTRUSTED_TOUCHES_TOAST, packageName)) {
+ if (ArrayUtils.contains(PACKAGE_BLOCKLIST_FOR_UNTRUSTED_TOUCHES_TOAST, packageName)) {
Log.i(TAG, "Suppressing untrusted touch toast for " + packageName);
return;
}
@@ -2245,6 +2352,46 @@
}
// Native callback.
+ private void notifySensorEvent(int deviceId, int sensorType, int accuracy, long timestamp,
+ float[] values) {
+ if (DEBUG) {
+ Slog.d(TAG, "notifySensorEvent: deviceId=" + deviceId + " sensorType="
+ + sensorType + " values=" + Arrays.toString(values));
+ }
+ mSensorEventListenersToNotify.clear();
+ final int numListeners;
+ synchronized (mSensorEventLock) {
+ numListeners = mSensorEventListeners.size();
+ for (int i = 0; i < numListeners; i++) {
+ mSensorEventListenersToNotify.add(
+ mSensorEventListeners.valueAt(i));
+ }
+ }
+ for (int i = 0; i < numListeners; i++) {
+ mSensorEventListenersToNotify.get(i).notifySensorEvent(deviceId, sensorType,
+ accuracy, timestamp, values);
+ }
+ mSensorEventListenersToNotify.clear();
+ }
+
+ // Native callback.
+ private void notifySensorAccuracy(int deviceId, int sensorType, int accuracy) {
+ mSensorAccuracyListenersToNotify.clear();
+ final int numListeners;
+ synchronized (mSensorEventLock) {
+ numListeners = mSensorEventListeners.size();
+ for (int i = 0; i < numListeners; i++) {
+ mSensorAccuracyListenersToNotify.add(mSensorEventListeners.valueAt(i));
+ }
+ }
+ for (int i = 0; i < numListeners; i++) {
+ mSensorAccuracyListenersToNotify.get(i).notifySensorAccuracy(
+ deviceId, sensorType, accuracy);
+ }
+ mSensorAccuracyListenersToNotify.clear();
+ }
+
+ // Native callback.
final boolean filterInputEvent(InputEvent event, int policyFlags) {
synchronized (mInputFilterLock) {
if (mInputFilter != null) {
@@ -2592,17 +2739,8 @@
/**
* Called when the focused window has changed.
- *
- * @return true if we want to request a configuration refresh.
*/
- boolean notifyFocusChanged(IBinder oldToken, IBinder newToken);
-
- /**
- * Called by the client to request pointer capture.
- *
- * @return true if we want to request a configuration refresh.
- */
- boolean requestPointerCapture(IBinder windowToken, boolean enabled);
+ void notifyFocusChanged(IBinder oldToken, IBinder newToken);
}
/**
@@ -2785,6 +2923,56 @@
}
}
+ private void onSensorEventListenerDied(int pid) {
+ synchronized (mSensorEventLock) {
+ mSensorEventListeners.remove(pid);
+ }
+ }
+
+ private final class SensorEventListenerRecord implements DeathRecipient {
+ private final int mPid;
+ private final IInputSensorEventListener mListener;
+
+ SensorEventListenerRecord(int pid, IInputSensorEventListener listener) {
+ mPid = pid;
+ mListener = listener;
+ }
+
+ @Override
+ public void binderDied() {
+ if (DEBUG) {
+ Slog.d(TAG, "Sensor event listener for pid " + mPid + " died.");
+ }
+ onSensorEventListenerDied(mPid);
+ }
+
+ public IInputSensorEventListener getListener() {
+ return mListener;
+ }
+
+ public void notifySensorEvent(int deviceId, int sensorType, int accuracy, long timestamp,
+ float[] values) {
+ try {
+ mListener.onInputSensorChanged(deviceId, sensorType, accuracy, timestamp,
+ values);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to notify process " + mPid
+ + " that sensor event notified, assuming it died.", ex);
+ binderDied();
+ }
+ }
+
+ public void notifySensorAccuracy(int deviceId, int sensorType, int accuracy) {
+ try {
+ mListener.onInputSensorAccuracyChanged(deviceId, sensorType, accuracy);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to notify process " + mPid
+ + " that sensor accuracy notified, assuming it died.", ex);
+ binderDied();
+ }
+ }
+ }
+
private final class VibratorToken implements DeathRecipient {
public final int mDeviceId;
public final IBinder mToken;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 90edd77..ab7e3b0 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -162,7 +162,11 @@
import com.android.internal.inputmethod.IBooleanResultCallback;
import com.android.internal.inputmethod.IInputBindResultResultCallback;
import com.android.internal.inputmethod.IInputContentUriToken;
+import com.android.internal.inputmethod.IInputMethodInfoListResultCallback;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
+import com.android.internal.inputmethod.IInputMethodSubtypeListResultCallback;
+import com.android.internal.inputmethod.IInputMethodSubtypeResultCallback;
+import com.android.internal.inputmethod.IIntResultCallback;
import com.android.internal.inputmethod.InputMethodDebug;
import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.inputmethod.StartInputFlags;
@@ -1970,43 +1974,51 @@
}
@Override
- public List<InputMethodInfo> getInputMethodList(@UserIdInt int userId) {
- if (UserHandle.getCallingUserId() != userId) {
- mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
- }
- synchronized (mMethodMap) {
- final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
- mSettings.getCurrentUserId(), null);
- if (resolvedUserIds.length != 1) {
- return Collections.emptyList();
+ public void getInputMethodList(@UserIdInt int userId,
+ IInputMethodInfoListResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback, () -> {
+ if (UserHandle.getCallingUserId() != userId) {
+ mContext.enforceCallingPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
}
- final long ident = Binder.clearCallingIdentity();
- try {
- return getInputMethodListLocked(resolvedUserIds[0]);
- } finally {
- Binder.restoreCallingIdentity(ident);
+ synchronized (mMethodMap) {
+ final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
+ mSettings.getCurrentUserId(), null);
+ if (resolvedUserIds.length != 1) {
+ return Collections.emptyList();
+ }
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return getInputMethodListLocked(resolvedUserIds[0]);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
- }
+ });
}
@Override
- public List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) {
- if (UserHandle.getCallingUserId() != userId) {
- mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
- }
- synchronized (mMethodMap) {
- final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
- mSettings.getCurrentUserId(), null);
- if (resolvedUserIds.length != 1) {
- return Collections.emptyList();
+ public void getEnabledInputMethodList(@UserIdInt int userId,
+ IInputMethodInfoListResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback, () -> {
+ if (UserHandle.getCallingUserId() != userId) {
+ mContext.enforceCallingPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
}
- final long ident = Binder.clearCallingIdentity();
- try {
- return getEnabledInputMethodListLocked(resolvedUserIds[0]);
- } finally {
- Binder.restoreCallingIdentity(ident);
+ synchronized (mMethodMap) {
+ final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
+ mSettings.getCurrentUserId(), null);
+ if (resolvedUserIds.length != 1) {
+ return Collections.emptyList();
+ }
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return getEnabledInputMethodListLocked(resolvedUserIds[0]);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
- }
+ });
}
@GuardedBy("mMethodMap")
@@ -2159,27 +2171,34 @@
}
/**
- * @param imiId if null, returns enabled subtypes for the current imi
- * @return enabled subtypes of the specified imi
+ * Gets enabled subtypes of the specified {@link InputMethodInfo}.
+ *
+ * @param imiId if null, returns enabled subtypes for the current {@link InputMethodInfo}.
+ * @param allowsImplicitlySelectedSubtypes {@code true} to return the implicitly selected
+ * subtypes.
+ * @param resultCallback to callback the result.
*/
@Override
- public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
- boolean allowsImplicitlySelectedSubtypes) {
- final int callingUserId = UserHandle.getCallingUserId();
- synchronized (mMethodMap) {
- final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
- mSettings.getCurrentUserId(), null);
- if (resolvedUserIds.length != 1) {
- return Collections.emptyList();
+ public void getEnabledInputMethodSubtypeList(String imiId,
+ boolean allowsImplicitlySelectedSubtypes,
+ IInputMethodSubtypeListResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback, () -> {
+ final int callingUserId = UserHandle.getCallingUserId();
+ synchronized (mMethodMap) {
+ final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
+ mSettings.getCurrentUserId(), null);
+ if (resolvedUserIds.length != 1) {
+ return Collections.emptyList();
+ }
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return getEnabledInputMethodSubtypeListLocked(imiId,
+ allowsImplicitlySelectedSubtypes, resolvedUserIds[0]);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
- final long ident = Binder.clearCallingIdentity();
- try {
- return getEnabledInputMethodSubtypeListLocked(imiId,
- allowsImplicitlySelectedSubtypes, resolvedUserIds[0]);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
+ });
}
@GuardedBy("mMethodMap")
@@ -3892,29 +3911,31 @@
}
@Override
- public InputMethodSubtype getLastInputMethodSubtype() {
- synchronized (mMethodMap) {
- if (!calledFromValidUserLocked()) {
- return null;
- }
- final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
- // TODO: Handle the case of the last IME with no subtypes
- if (lastIme == null || TextUtils.isEmpty(lastIme.first)
- || TextUtils.isEmpty(lastIme.second)) return null;
- final InputMethodInfo lastImi = mMethodMap.get(lastIme.first);
- if (lastImi == null) return null;
- try {
- final int lastSubtypeHash = Integer.parseInt(lastIme.second);
- final int lastSubtypeId =
- InputMethodUtils.getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
- if (lastSubtypeId < 0 || lastSubtypeId >= lastImi.getSubtypeCount()) {
+ public void getLastInputMethodSubtype(IInputMethodSubtypeResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback, () -> {
+ synchronized (mMethodMap) {
+ if (!calledFromValidUserLocked()) {
return null;
}
- return lastImi.getSubtypeAt(lastSubtypeId);
- } catch (NumberFormatException e) {
- return null;
+ final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
+ // TODO: Handle the case of the last IME with no subtypes
+ if (lastIme == null || TextUtils.isEmpty(lastIme.first)
+ || TextUtils.isEmpty(lastIme.second)) return null;
+ final InputMethodInfo lastImi = mMethodMap.get(lastIme.first);
+ if (lastImi == null) return null;
+ try {
+ final int lastSubtypeHash = Integer.parseInt(lastIme.second);
+ final int lastSubtypeId =
+ InputMethodUtils.getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
+ if (lastSubtypeId < 0 || lastSubtypeId >= lastImi.getSubtypeCount()) {
+ return null;
+ }
+ return lastImi.getSubtypeAt(lastSubtypeId);
+ } catch (NumberFormatException e) {
+ return null;
+ }
}
- }
+ });
}
@Override
@@ -3981,9 +4002,11 @@
* @return {@link WindowManagerInternal#getInputMethodWindowVisibleHeight(int)}
*/
@Override
- public int getInputMethodWindowVisibleHeight() {
- // TODO(yukawa): Should we verify the display ID?
- return mWindowManagerInternal.getInputMethodWindowVisibleHeight(mCurTokenDisplayId);
+ public void getInputMethodWindowVisibleHeight(IIntResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback, () -> {
+ // TODO(yukawa): Should we verify the display ID?
+ return mWindowManagerInternal.getInputMethodWindowVisibleHeight(mCurTokenDisplayId);
+ });
}
@Override
@@ -4950,17 +4973,21 @@
}
/**
- * @return Return the current subtype of this input method.
+ * Gets the current subtype of this input method.
+ *
+ * @param resultCallback to callback the result.
*/
@Override
- public InputMethodSubtype getCurrentInputMethodSubtype() {
- synchronized (mMethodMap) {
- // TODO: Make this work even for non-current users?
- if (!calledFromValidUserLocked()) {
- return null;
+ public void getCurrentInputMethodSubtype(IInputMethodSubtypeResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback, () -> {
+ synchronized (mMethodMap) {
+ // TODO: Make this work even for non-current users?
+ if (!calledFromValidUserLocked()) {
+ return null;
+ }
+ return getCurrentInputMethodSubtypeLocked();
}
- return getCurrentInputMethodSubtypeLocked();
- }
+ });
}
InputMethodSubtype getCurrentInputMethodSubtypeLocked() {
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index ccb78a4..3485881 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -75,6 +75,10 @@
import com.android.internal.inputmethod.CallbackUtils;
import com.android.internal.inputmethod.IBooleanResultCallback;
import com.android.internal.inputmethod.IInputBindResultResultCallback;
+import com.android.internal.inputmethod.IInputMethodInfoListResultCallback;
+import com.android.internal.inputmethod.IInputMethodSubtypeListResultCallback;
+import com.android.internal.inputmethod.IInputMethodSubtypeResultCallback;
+import com.android.internal.inputmethod.IIntResultCallback;
import com.android.internal.inputmethod.IMultiClientInputMethod;
import com.android.internal.inputmethod.IMultiClientInputMethodPrivilegedOperations;
import com.android.internal.inputmethod.IMultiClientInputMethodSession;
@@ -1457,35 +1461,42 @@
@BinderThread
@Override
- public List<InputMethodInfo> getInputMethodList(@UserIdInt int userId) {
- if (UserHandle.getCallingUserId() != userId) {
- mContext.enforceCallingPermission(INTERACT_ACROSS_USERS_FULL, null);
- }
- return mInputMethodInfoMap.getAsList(userId);
+ public void getInputMethodList(@UserIdInt int userId,
+ IInputMethodInfoListResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback, () -> {
+ if (UserHandle.getCallingUserId() != userId) {
+ mContext.enforceCallingPermission(INTERACT_ACROSS_USERS_FULL, null);
+ }
+ return mInputMethodInfoMap.getAsList(userId);
+ });
}
@BinderThread
@Override
- public List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) {
- if (UserHandle.getCallingUserId() != userId) {
- mContext.enforceCallingPermission(INTERACT_ACROSS_USERS_FULL, null);
- }
- return mInputMethodInfoMap.getAsList(userId);
+ public void getEnabledInputMethodList(@UserIdInt int userId,
+ IInputMethodInfoListResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback, () -> {
+ if (UserHandle.getCallingUserId() != userId) {
+ mContext.enforceCallingPermission(INTERACT_ACROSS_USERS_FULL, null);
+ }
+ return mInputMethodInfoMap.getAsList(userId);
+ });
}
@BinderThread
@Override
- public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
- boolean allowsImplicitlySelectedSubtypes) {
+ public void getEnabledInputMethodSubtypeList(String imiId,
+ boolean allowsImplicitlySelectedSubtypes,
+ IInputMethodSubtypeListResultCallback resultCallback) {
reportNotSupported();
- return Collections.emptyList();
+ CallbackUtils.onResult(resultCallback, Collections::emptyList);
}
@BinderThread
@Override
- public InputMethodSubtype getLastInputMethodSubtype() {
+ public void getLastInputMethodSubtype(IInputMethodSubtypeResultCallback resultCallback) {
reportNotSupported();
- return null;
+ CallbackUtils.onResult(resultCallback, () -> null);
}
@BinderThread
@@ -1793,9 +1804,9 @@
@BinderThread
@Override
- public InputMethodSubtype getCurrentInputMethodSubtype() {
+ public void getCurrentInputMethodSubtype(IInputMethodSubtypeResultCallback resultCallback) {
reportNotSupported();
- return null;
+ CallbackUtils.onResult(resultCallback, () -> null);
}
@BinderThread
@@ -1806,9 +1817,9 @@
@BinderThread
@Override
- public int getInputMethodWindowVisibleHeight() {
+ public void getInputMethodWindowVisibleHeight(IIntResultCallback resultCallback) {
reportNotSupported();
- return 0;
+ CallbackUtils.onResult(resultCallback, () -> 0);
}
@BinderThread
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 324332f..9068287 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -47,7 +47,7 @@
import android.location.Geofence;
import android.location.GnssCapabilities;
import android.location.GnssMeasurementCorrections;
-import android.location.GnssRequest;
+import android.location.GnssMeasurementRequest;
import android.location.IGeocodeListener;
import android.location.IGnssAntennaInfoListener;
import android.location.IGnssMeasurementsListener;
@@ -859,7 +859,7 @@
}
@Override
- public void addGnssMeasurementsListener(@Nullable GnssRequest request,
+ public void addGnssMeasurementsListener(@Nullable GnssMeasurementRequest request,
IGnssMeasurementsListener listener, String packageName, String attributionTag) {
if (mGnssManagerService != null) {
mGnssManagerService.addGnssMeasurementsListener(request, listener, packageName,
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
index 20458b4..cc510fb 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
@@ -39,6 +39,10 @@
import com.android.server.location.ClientBrokerProto;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
@@ -119,6 +123,13 @@
private final boolean mHasAccessContextHubPermission;
/*
+ * The set of nanoapp IDs that represent the group of nanoapps this client has a messaging
+ * channel with, i.e. has sent or received messages from this particular nanoapp.
+ */
+ private final Set<Long> mMessageChannelNanoappIdSet =
+ Collections.newSetFromMap(new ConcurrentHashMap<Long, Boolean>());
+
+ /*
* Helper class to manage registered PendingIntent requests from the client.
*/
private class PendingIntentRequest {
@@ -134,7 +145,8 @@
private boolean mValid = false;
- PendingIntentRequest() {}
+ PendingIntentRequest() {
+ }
PendingIntentRequest(PendingIntent pendingIntent, long nanoAppId) {
mPendingIntent = pendingIntent;
@@ -177,7 +189,7 @@
mPackage = mContext.getPackageManager().getNameForUid(Binder.getCallingUid());
mHasAccessContextHubPermission = context.checkCallingPermission(
- Manifest.permission.ACCESS_CONTEXT_HUB) == PERMISSION_GRANTED;
+ Manifest.permission.ACCESS_CONTEXT_HUB) == PERMISSION_GRANTED;
}
/* package */ ContextHubClientBroker(
@@ -193,7 +205,7 @@
mPackage = pendingIntent.getCreatorPackage();
mHasAccessContextHubPermission = context.checkCallingPermission(
- Manifest.permission.ACCESS_CONTEXT_HUB) == PERMISSION_GRANTED;
+ Manifest.permission.ACCESS_CONTEXT_HUB) == PERMISSION_GRANTED;
}
/**
@@ -209,6 +221,7 @@
int result;
if (isRegistered()) {
+ mMessageChannelNanoappIdSet.add(message.getNanoAppId());
ContextHubMsg messageToNanoApp =
ContextHubServiceUtil.createHidlContextHubMessage(mHostEndPointId, message);
@@ -269,6 +282,7 @@
* @param message the message that came from a nanoapp
*/
/* package */ void sendMessageToClient(NanoAppMessage message) {
+ mMessageChannelNanoappIdSet.add(message.getNanoAppId());
invokeCallback(callback -> callback.onMessageFromNanoApp(message));
Supplier<Intent> supplier =
@@ -413,7 +427,7 @@
/**
* Sends an intent to any existing PendingIntent
*
- * @param supplier method to create the extra Intent
+ * @param supplier method to create the extra Intent
* @param nanoAppId the ID of the nanoapp which this event is for
*/
private synchronized void sendPendingIntent(Supplier<Intent> supplier, long nanoAppId) {
@@ -427,7 +441,7 @@
* Sends a PendingIntent with extra Intent data
*
* @param pendingIntent the PendingIntent
- * @param intent the extra Intent data
+ * @param intent the extra Intent data
*/
private void doSendPendingIntent(PendingIntent pendingIntent, Intent intent) {
try {
@@ -500,6 +514,17 @@
} else {
out += "package: " + mPackage;
}
+ if (mMessageChannelNanoappIdSet.size() > 0) {
+ out += " messageChannelNanoappSet: (";
+ Iterator<Long> it = mMessageChannelNanoappIdSet.iterator();
+ while (it.hasNext()) {
+ out += "0x" + Long.toHexString(it.next());
+ if (it.hasNext()) {
+ out += ",";
+ }
+ }
+ out += ")";
+ }
out += "]";
return out;
diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
index 326265f..fa137aa 100644
--- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java
+++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
@@ -21,9 +21,9 @@
import android.content.Context;
import android.location.GnssAntennaInfo;
import android.location.GnssMeasurementCorrections;
+import android.location.GnssMeasurementRequest;
import android.location.GnssMeasurementsEvent;
import android.location.GnssNavigationMessage;
-import android.location.GnssRequest;
import android.location.IGnssAntennaInfoListener;
import android.location.IGnssMeasurementsListener;
import android.location.IGnssNavigationMessageListener;
@@ -176,12 +176,10 @@
/**
* Adds a GNSS measurements listener.
*/
- public void addGnssMeasurementsListener(GnssRequest request, IGnssMeasurementsListener listener,
- String packageName, @Nullable String attributionTag) {
+ public void addGnssMeasurementsListener(GnssMeasurementRequest request,
+ IGnssMeasurementsListener listener, String packageName,
+ @Nullable String attributionTag) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
- if (request.isFullTracking()) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
- }
CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag);
mGnssMeasurementsProvider.addListener(request, identity, listener);
diff --git a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
index 59a533c..fa8e2a6 100644
--- a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
@@ -21,8 +21,8 @@
import android.annotation.Nullable;
import android.app.AppOpsManager;
+import android.location.GnssMeasurementRequest;
import android.location.GnssMeasurementsEvent;
-import android.location.GnssRequest;
import android.location.IGnssMeasurementsListener;
import android.location.util.identity.CallerIdentity;
import android.os.IBinder;
@@ -47,18 +47,18 @@
* @hide
*/
public final class GnssMeasurementsProvider extends
- GnssListenerMultiplexer<GnssRequest, IGnssMeasurementsListener, Boolean> implements
- SettingsHelper.GlobalSettingChangedListener {
+ GnssListenerMultiplexer<GnssMeasurementRequest, IGnssMeasurementsListener, Boolean>
+ implements SettingsHelper.GlobalSettingChangedListener {
private class GnssMeasurementListenerRegistration extends GnssListenerRegistration {
private static final String GNSS_MEASUREMENTS_BUCKET = "gnss_measurement";
protected GnssMeasurementListenerRegistration(
- @Nullable GnssRequest gnssRequest,
+ @Nullable GnssMeasurementRequest request,
CallerIdentity callerIdentity,
IGnssMeasurementsListener iGnssMeasurementsListener) {
- super(gnssRequest, callerIdentity, iGnssMeasurementsListener);
+ super(request, callerIdentity, iGnssMeasurementsListener);
}
@Nullable
@@ -100,13 +100,13 @@
}
@Override
- public void addListener(GnssRequest request, CallerIdentity identity,
+ public void addListener(GnssMeasurementRequest request, CallerIdentity identity,
IGnssMeasurementsListener listener) {
super.addListener(request, identity, listener);
}
@Override
- protected GnssListenerRegistration createRegistration(GnssRequest request,
+ protected GnssListenerRegistration createRegistration(GnssMeasurementRequest request,
CallerIdentity callerIdentity, IGnssMeasurementsListener listener) {
return new GnssMeasurementListenerRegistration(request, callerIdentity, listener);
}
diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
index 7afa81a..8a13969 100644
--- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java
+++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
@@ -439,6 +439,7 @@
}
}
}
+
private class BluetoothBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 4be7689..17ceb15 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -16,6 +16,7 @@
package com.android.server.media;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.os.UserHandle.ALL;
import static android.os.UserHandle.CURRENT;
@@ -1115,8 +1116,7 @@
final long token = Binder.clearCallingIdentity();
try {
enforcePackageName(packageName, uid);
- int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
- false /* allowAll */, true /* requireFull */, "createSession", packageName);
+ int resolvedUserId = handleIncomingUser(pid, uid, userId, packageName);
if (cb == null) {
throw new IllegalArgumentException("Controller callback cannot be null");
}
@@ -1191,11 +1191,8 @@
final long token = Binder.clearCallingIdentity();
try {
- // Check that they can make calls on behalf of the user and
- // get the final user id
- int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
- true /* allowAll */, true /* requireFull */, "getSession2Tokens",
- null /* optional packageName */);
+ // Check that they can make calls on behalf of the user and get the final user id
+ int resolvedUserId = handleIncomingUser(pid, uid, userId, null);
List<Session2Token> result;
synchronized (mLock) {
FullUserRecord user = getFullUserRecordLocked(userId);
@@ -1262,9 +1259,7 @@
try {
// Check that they can make calls on behalf of the user and get the final user id.
- int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
- true /* allowAll */, true /* requireFull */, "addSession2TokensListener",
- null /* optional packageName */);
+ int resolvedUserId = handleIncomingUser(pid, uid, userId, null);
synchronized (mLock) {
int index = findIndexOfSession2TokensListenerLocked(listener);
if (index >= 0) {
@@ -1981,16 +1976,40 @@
packageName = componentName.getPackageName();
enforcePackageName(packageName, uid);
}
- // Check that they can make calls on behalf of the user and
- // get the final user id
- int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
- true /* allowAll */, true /* requireFull */, "getSessions", packageName);
- // Check if they have the permissions or their component is
- // enabled for the user they're calling from.
+ // Check that they can make calls on behalf of the user and get the final user id
+ int resolvedUserId = handleIncomingUser(pid, uid, userId, packageName);
+ // Check if they have the permissions or their component is enabled for the user
+ // they're calling from.
enforceMediaPermissions(componentName, pid, uid, resolvedUserId);
return resolvedUserId;
}
+ // Handles incoming user by checking whether the caller has permission to access the
+ // given user id's information or not. Permission is not necessary if the given user id is
+ // equal to the caller's user id, but if not, the caller needs to have the
+ // INTERACT_ACROSS_USERS_FULL permission. Otherwise, a security exception will be thrown.
+ // The return value will be the given user id, unless the given user id is
+ // UserHandle.CURRENT, which will return the ActivityManager.getCurrentUser() value instead.
+ private int handleIncomingUser(int pid, int uid, int userId, String packageName) {
+ int callingUserId = UserHandle.getUserHandleForUid(uid).getIdentifier();
+ if (userId == callingUserId) {
+ return userId;
+ }
+
+ boolean canInteractAcrossUsersFull = mContext.checkPermission(
+ INTERACT_ACROSS_USERS_FULL, pid, uid) == PackageManager.PERMISSION_GRANTED;
+ if (canInteractAcrossUsersFull) {
+ if (userId == CURRENT.getIdentifier()) {
+ return ActivityManager.getCurrentUser();
+ }
+ return userId;
+ }
+
+ throw new SecurityException("Permission denied while calling from " + packageName
+ + " with user id: " + userId + "; Need to run as either the calling user id ("
+ + callingUserId + "), or with " + INTERACT_ACROSS_USERS_FULL + " permission");
+ }
+
private boolean hasEnabledNotificationListener(int callingUserId,
String controllerPackageName, int controllerUid) {
int controllerUserId = UserHandle.getUserHandleForUid(controllerUid).getIdentifier();
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 342a11b..c4beddd4 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -28,9 +28,9 @@
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_REMOVED;
-import static android.net.NetworkUtils.multiplySafeByRational;
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
+import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational;
import static com.android.server.net.NetworkStatsService.TAG;
import android.net.NetworkIdentity;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d3d998a..c9ed518 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -6363,6 +6363,7 @@
private final int mRank;
private final int mCount;
private final ManagedServiceInfo mListener;
+ private final long mWhen;
CancelNotificationRunnable(final int callingUid, final int callingPid,
final String pkg, final String tag, final int id,
@@ -6382,6 +6383,7 @@
this.mRank = rank;
this.mCount = count;
this.mListener = listener;
+ this.mWhen = System.currentTimeMillis();
}
@Override
@@ -6393,8 +6395,33 @@
}
synchronized (mNotificationLock) {
- // Look for the notification, searching both the posted and enqueued lists.
- NotificationRecord r = findNotificationLocked(mPkg, mTag, mId, mUserId);
+ // Check to see if there is a notification in the enqueued list that hasn't had a
+ // chance to post yet.
+ List<NotificationRecord> enqueued = findEnqueuedNotificationsForCriteria(
+ mPkg, mTag, mId, mUserId);
+ boolean repost = false;
+ if (enqueued.size() > 0) {
+ // Found something, let's see what it was
+ repost = true;
+ // If all enqueues happened before this cancel then wait for them to happen,
+ // otherwise we should let this cancel through so the next enqueue happens
+ for (NotificationRecord r : enqueued) {
+ if (r.mUpdateTimeMs > mWhen) {
+ // At least one enqueue was posted after the cancel, so we're invalid
+ Slog.i(TAG, "notification cancel ignored due to newer enqueued entry"
+ + "key=" + r.getSbn().getKey());
+ return;
+ }
+ }
+ }
+ if (repost) {
+ mHandler.post(this);
+ return;
+ }
+
+ // Look for the notification in the posted list, since we already checked enqueued.
+ NotificationRecord r =
+ findNotificationByListLocked(mNotificationList, mPkg, mTag, mId, mUserId);
if (r != null) {
// The notification was found, check if it should be removed.
@@ -6417,6 +6444,10 @@
if ((r.getNotification().flags & mMustNotHaveFlags) != 0) {
return;
}
+ if (r.getUpdateTimeMs() > mWhen) {
+ // In this case, a post must have slipped by when this runnable reposted
+ return;
+ }
// Bubbled children get to stick around if the summary was manually cancelled
// (user removed) from systemui.
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index b131aff..094be06 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -55,6 +55,12 @@
import com.android.server.compat.CompatChange;
import com.android.server.om.OverlayReferenceMapper;
import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.utils.Snappable;
+import com.android.server.utils.Snapshots;
+import com.android.server.utils.Watchable;
+import com.android.server.utils.WatchableImpl;
+import com.android.server.utils.WatchedArrayMap;
+import com.android.server.utils.Watcher;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -69,7 +75,7 @@
* manifests.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-public class AppsFilter {
+public class AppsFilter implements Watchable, Snappable {
private static final String TAG = "AppsFilter";
@@ -145,6 +151,55 @@
@GuardedBy("mCacheLock")
private volatile SparseArray<SparseBooleanArray> mShouldFilterCache;
+ /**
+ * A cached snapshot.
+ */
+ private volatile AppsFilter mSnapshot = null;
+
+ /**
+ * Watchable machinery
+ */
+ private final WatchableImpl mWatchable = new WatchableImpl();
+
+ /**
+ * Ensures an observer is in the list, exactly once. The observer cannot be null. The
+ * function quietly returns if the observer is already in the list.
+ *
+ * @param observer The {@link Watcher} to be notified when the {@link Watchable} changes.
+ */
+ public void registerObserver(@NonNull Watcher observer) {
+ mWatchable.registerObserver(observer);
+ }
+
+ /**
+ * Ensures an observer is not in the list. The observer must not be null. The function
+ * quietly returns if the objserver is not in the list.
+ *
+ * @param observer The {@link Watcher} that should not be in the notification list.
+ */
+ public void unregisterObserver(@NonNull Watcher observer) {
+ mWatchable.unregisterObserver(observer);
+ }
+
+ /**
+ * Invokes {@link Watcher#onChange} on each registered observer. The method can be called
+ * with the {@link Watchable} that generated the event. In a tree of {@link Watchable}s, this
+ * is generally the first (deepest) {@link Watchable} to detect a change.
+ *
+ * @param what The {@link Watchable} that generated the event.
+ */
+ public void dispatchChange(@Nullable Watchable what) {
+ mSnapshot = null;
+ mWatchable.dispatchChange(what);
+ }
+
+ /**
+ * Report a change to observers.
+ */
+ private void onChanged() {
+ dispatchChange(this);
+ }
+
@VisibleForTesting(visibility = PRIVATE)
AppsFilter(StateProvider stateProvider,
FeatureConfig featureConfig,
@@ -162,6 +217,44 @@
}
/**
+ * The copy constructor is used by PackageManagerService to construct a snapshot.
+ * Attributes are not deep-copied since these are supposed to be immutable.
+ * TODO: deep-copy the attributes, if necessary.
+ */
+ private AppsFilter(AppsFilter orig) {
+ Snapshots.copy(mImplicitlyQueryable, orig.mImplicitlyQueryable);
+ Snapshots.copy(mQueriesViaPackage, orig.mQueriesViaPackage);
+ Snapshots.copy(mQueriesViaComponent, orig.mQueriesViaComponent);
+ mQueriesViaComponentRequireRecompute = orig.mQueriesViaComponentRequireRecompute;
+ mForceQueryable.addAll(orig.mForceQueryable);
+ mForceQueryableByDevicePackageNames = orig.mForceQueryableByDevicePackageNames;
+ mSystemAppsQueryable = orig.mSystemAppsQueryable;
+ mFeatureConfig = orig.mFeatureConfig;
+ mOverlayReferenceMapper = orig.mOverlayReferenceMapper;
+ mStateProvider = orig.mStateProvider;
+ mSystemSigningDetails = orig.mSystemSigningDetails;
+ mProtectedBroadcasts = orig.mProtectedBroadcasts;
+ mShouldFilterCache = orig.mShouldFilterCache;
+
+ mBackgroundExecutor = null;
+ }
+
+ /**
+ * Return a snapshot. If the cached snapshot is null, build a new one. The logic in
+ * the function ensures that this function returns a valid snapshot even if a race
+ * condition causes the cached snapshot to be cleared asynchronously to this method.
+ */
+ public AppsFilter snapshot() {
+ AppsFilter s = mSnapshot;
+ if (s == null) {
+ s = new AppsFilter(this);
+ s.mWatchable.seal();
+ mSnapshot = s;
+ }
+ return s;
+ }
+
+ /**
* Provides system state to AppsFilter via {@link CurrentStateCallback} after properly guarding
* the data with the package lock.
*/
@@ -311,6 +404,9 @@
} else {
mDisabledPackages.add(pkg.getPackageName());
}
+ if (mAppsFilter != null) {
+ mAppsFilter.onChanged();
+ }
}
@Override
@@ -347,7 +443,7 @@
}
final StateProvider stateProvider = command -> {
synchronized (injector.getLock()) {
- command.currentState(injector.getSettings().getPackagesLocked(),
+ command.currentState(injector.getSettings().getPackagesLocked().untrackedMap(),
injector.getUserManagerInternal().getUserInfos());
}
};
@@ -482,7 +578,8 @@
*/
public void grantImplicitAccess(int recipientUid, int visibleUid) {
if (recipientUid != visibleUid) {
- if (mImplicitlyQueryable.add(recipientUid, visibleUid) && DEBUG_LOGGING) {
+ final boolean changed = mImplicitlyQueryable.add(recipientUid, visibleUid);
+ if (changed && DEBUG_LOGGING) {
Slog.i(TAG, "implicit access granted: " + recipientUid + " -> " + visibleUid);
}
synchronized (mCacheLock) {
@@ -497,6 +594,9 @@
visibleUids.put(visibleUid, false);
}
}
+ if (changed) {
+ onChanged();
+ }
}
}
@@ -505,6 +605,7 @@
mFeatureConfig.onSystemReady();
updateEntireShouldFilterCacheAsync();
+ onChanged();
}
/**
@@ -530,6 +631,7 @@
}
});
} finally {
+ onChanged();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
@@ -712,6 +814,7 @@
synchronized (mCacheLock) {
if (mShouldFilterCache != null) {
updateEntireShouldFilterCache();
+ onChanged();
}
}
}
@@ -870,6 +973,16 @@
}
/**
+ * This api does type conversion on the <existingSettings> parameter.
+ */
+ @VisibleForTesting(visibility = PRIVATE)
+ @Nullable
+ SparseArray<int[]> getVisibilityAllowList(PackageSetting setting, int[] users,
+ WatchedArrayMap<String, PackageSetting> existingSettings) {
+ return getVisibilityAllowList(setting, users, existingSettings.untrackedMap());
+ }
+
+ /**
* Equivalent to calling {@link #addPackage(PackageSetting, boolean)} with {@code isReplace}
* equal to {@code false}.
* @see AppsFilter#addPackage(PackageSetting, boolean)
@@ -946,6 +1059,7 @@
siblingSetting, settings, users, settings.size());
}
}
+ onChanged();
}
});
}
diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
index 8e6b89a..bf7f466 100644
--- a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
+++ b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
@@ -14,21 +14,22 @@
* limitations under the License.
*/
-
package com.android.server.pm;
-
import android.annotation.NonNull;
import android.content.IntentFilter;
-import com.android.server.IntentResolver;
+import com.android.server.utils.Snappable;
+import com.android.server.utils.WatchableIntentResolver;
+
import java.util.List;
/**
* Used to find a list of {@link CrossProfileIntentFilter}s that match an intent.
*/
class CrossProfileIntentResolver
- extends IntentResolver<CrossProfileIntentFilter, CrossProfileIntentFilter> {
+ extends WatchableIntentResolver<CrossProfileIntentFilter, CrossProfileIntentFilter>
+ implements Snappable {
@Override
protected CrossProfileIntentFilter[] newArray(int size) {
return new CrossProfileIntentFilter[size];
@@ -48,4 +49,15 @@
protected IntentFilter getIntentFilter(@NonNull CrossProfileIntentFilter input) {
return input;
}
+
+ /**
+ * Return a snapshot of the current object. The snapshot is a read-only copy suitable
+ * for read-only methods.
+ * @return A snapshot of the current object.
+ */
+ public CrossProfileIntentResolver snapshot() {
+ CrossProfileIntentResolver result = new CrossProfileIntentResolver();
+ result.doCopy(this);
+ return result;
+ }
}
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index a09640d..69d3e5c 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -24,6 +24,7 @@
import android.content.pm.InstantAppInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
+import android.content.pm.PermissionInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
@@ -36,13 +37,13 @@
import android.os.Message;
import android.os.UserHandle;
import android.os.storage.StorageManager;
+import android.permission.PermissionManager;
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.PackageUtils;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.SparseBooleanArray;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
@@ -55,20 +56,23 @@
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.utils.Snappable;
+import com.android.server.utils.Watchable;
+import com.android.server.utils.WatchableImpl;
+import com.android.server.utils.WatchedSparseArray;
+import com.android.server.utils.WatchedSparseBooleanArray;
+import com.android.server.utils.Watcher;
import libcore.io.IoUtils;
import libcore.util.HexEncoding;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
@@ -82,7 +86,7 @@
* pruning installed instant apps and meta-data for uninstalled instant apps
* when free space is needed.
*/
-class InstantAppRegistry {
+class InstantAppRegistry implements Watchable, Snappable {
private static final boolean DEBUG = false;
private static final String LOG_TAG = "InstantAppRegistry";
@@ -120,7 +124,7 @@
/** State for uninstalled instant apps */
@GuardedBy("mService.mLock")
- private SparseArray<List<UninstalledInstantAppState>> mUninstalledInstantApps;
+ private final WatchedSparseArray<List<UninstalledInstantAppState>> mUninstalledInstantApps;
/**
* Automatic grants for access to instant app metadata.
@@ -129,17 +133,90 @@
* UserID -> TargetAppId -> InstantAppId
*/
@GuardedBy("mService.mLock")
- private SparseArray<SparseArray<SparseBooleanArray>> mInstantGrants;
+ private final WatchedSparseArray<WatchedSparseArray<WatchedSparseBooleanArray>> mInstantGrants;
/** The set of all installed instant apps. UserID -> AppID */
@GuardedBy("mService.mLock")
- private SparseArray<SparseBooleanArray> mInstalledInstantAppUids;
+ private final WatchedSparseArray<WatchedSparseBooleanArray> mInstalledInstantAppUids;
+
+ /**
+ * The cached snapshot
+ */
+ private volatile InstantAppRegistry mSnapshot = null;
+
+ /**
+ * Watchable machinery
+ */
+ private final WatchableImpl mWatchable = new WatchableImpl();
+ public void registerObserver(@NonNull Watcher observer) {
+ mWatchable.registerObserver(observer);
+ }
+ public void unregisterObserver(@NonNull Watcher observer) {
+ mWatchable.unregisterObserver(observer);
+ }
+ public void dispatchChange(@Nullable Watchable what) {
+ mSnapshot = null;
+ mWatchable.dispatchChange(what);
+ }
+ /**
+ * Notify listeners that this object has changed.
+ */
+ private void onChanged() {
+ dispatchChange(this);
+ }
+
+ /** The list of observers */
+ private final Watcher mObserver = new Watcher() {
+ @Override
+ public void onChange(@Nullable Watchable what) {
+ InstantAppRegistry.this.onChanged();
+ }
+ };
public InstantAppRegistry(PackageManagerService service,
PermissionManagerServiceInternal permissionManager) {
mService = service;
mPermissionManager = permissionManager;
mCookiePersistence = new CookiePersistence(BackgroundThread.getHandler().getLooper());
+
+ mUninstalledInstantApps = new WatchedSparseArray<List<UninstalledInstantAppState>>();
+ mInstantGrants = new WatchedSparseArray<WatchedSparseArray<WatchedSparseBooleanArray>>();
+ mInstalledInstantAppUids = new WatchedSparseArray<WatchedSparseBooleanArray>();
+
+ mUninstalledInstantApps.registerObserver(mObserver);
+ mInstantGrants.registerObserver(mObserver);
+ mInstalledInstantAppUids.registerObserver(mObserver);
+ }
+
+ /**
+ * The copy constructor is used by PackageManagerService to construct a snapshot.
+ */
+ private InstantAppRegistry(InstantAppRegistry r) {
+ mService = r.mService;
+ mPermissionManager = r.mPermissionManager;
+ mCookiePersistence = null;
+
+ mUninstalledInstantApps = new WatchedSparseArray<List<UninstalledInstantAppState>>(
+ r.mUninstalledInstantApps);
+ mInstantGrants = new WatchedSparseArray<WatchedSparseArray<WatchedSparseBooleanArray>>(
+ r.mInstantGrants);
+ mInstalledInstantAppUids = new WatchedSparseArray<WatchedSparseBooleanArray>(
+ r.mInstalledInstantAppUids);
+
+ // Do not register any observers. This is a clone
+ }
+
+ /**
+ * Return a snapshot: the value is the cached snapshot if available.
+ */
+ public InstantAppRegistry snapshot() {
+ InstantAppRegistry s = mSnapshot;
+ if (s == null) {
+ s = new InstantAppRegistry(this);
+ s.mWatchable.seal();
+ mSnapshot = s;
+ }
+ return s;
}
@GuardedBy("mService.mLock")
@@ -370,37 +447,20 @@
@GuardedBy("mService.mLock")
public void onUserRemovedLPw(int userId) {
- if (mUninstalledInstantApps != null) {
- mUninstalledInstantApps.remove(userId);
- if (mUninstalledInstantApps.size() <= 0) {
- mUninstalledInstantApps = null;
- }
- }
- if (mInstalledInstantAppUids != null) {
- mInstalledInstantAppUids.remove(userId);
- if (mInstalledInstantAppUids.size() <= 0) {
- mInstalledInstantAppUids = null;
- }
- }
- if (mInstantGrants != null) {
- mInstantGrants.remove(userId);
- if (mInstantGrants.size() <= 0) {
- mInstantGrants = null;
- }
- }
+ mUninstalledInstantApps.remove(userId);
+ mInstalledInstantAppUids.remove(userId);
+ mInstantGrants.remove(userId);
deleteDir(getInstantApplicationsDir(userId));
}
public boolean isInstantAccessGranted(@UserIdInt int userId, int targetAppId,
int instantAppId) {
- if (mInstantGrants == null) {
- return false;
- }
- final SparseArray<SparseBooleanArray> targetAppList = mInstantGrants.get(userId);
+ final WatchedSparseArray<WatchedSparseBooleanArray> targetAppList =
+ mInstantGrants.get(userId);
if (targetAppList == null) {
return false;
}
- final SparseBooleanArray instantGrantList = targetAppList.get(targetAppId);
+ final WatchedSparseBooleanArray instantGrantList = targetAppList.get(targetAppId);
if (instantGrantList == null) {
return false;
}
@@ -413,7 +473,7 @@
if (mInstalledInstantAppUids == null) {
return; // no instant apps installed; no need to grant
}
- SparseBooleanArray instantAppList = mInstalledInstantAppUids.get(userId);
+ WatchedSparseBooleanArray instantAppList = mInstalledInstantAppUids.get(userId);
if (instantAppList == null || !instantAppList.get(instantAppId)) {
return; // instant app id isn't installed; no need to grant
}
@@ -426,17 +486,14 @@
return; // launched via VIEW/BROWSABLE intent; no need to grant
}
}
- if (mInstantGrants == null) {
- mInstantGrants = new SparseArray<>();
- }
- SparseArray<SparseBooleanArray> targetAppList = mInstantGrants.get(userId);
+ WatchedSparseArray<WatchedSparseBooleanArray> targetAppList = mInstantGrants.get(userId);
if (targetAppList == null) {
- targetAppList = new SparseArray<>();
+ targetAppList = new WatchedSparseArray<>();
mInstantGrants.put(userId, targetAppList);
}
- SparseBooleanArray instantGrantList = targetAppList.get(recipientUid);
+ WatchedSparseBooleanArray instantGrantList = targetAppList.get(recipientUid);
if (instantGrantList == null) {
- instantGrantList = new SparseBooleanArray();
+ instantGrantList = new WatchedSparseBooleanArray();
targetAppList.put(recipientUid, instantGrantList);
}
instantGrantList.put(instantAppId, true /*granted*/);
@@ -444,15 +501,13 @@
@GuardedBy("mService.mLock")
public void addInstantAppLPw(@UserIdInt int userId, int instantAppId) {
- if (mInstalledInstantAppUids == null) {
- mInstalledInstantAppUids = new SparseArray<>();
- }
- SparseBooleanArray instantAppList = mInstalledInstantAppUids.get(userId);
+ WatchedSparseBooleanArray instantAppList = mInstalledInstantAppUids.get(userId);
if (instantAppList == null) {
- instantAppList = new SparseBooleanArray();
+ instantAppList = new WatchedSparseBooleanArray();
mInstalledInstantAppUids.put(userId, instantAppList);
}
instantAppList.put(instantAppId, true /*installed*/);
+ onChanged();
}
@GuardedBy("mService.mLock")
@@ -461,23 +516,28 @@
if (mInstalledInstantAppUids == null) {
return; // no instant apps on the system
}
- final SparseBooleanArray instantAppList = mInstalledInstantAppUids.get(userId);
+ final WatchedSparseBooleanArray instantAppList = mInstalledInstantAppUids.get(userId);
if (instantAppList == null) {
return;
}
- instantAppList.delete(instantAppId);
+ try {
+ instantAppList.delete(instantAppId);
- // remove any grants
- if (mInstantGrants == null) {
- return; // no grants on the system
- }
- final SparseArray<SparseBooleanArray> targetAppList = mInstantGrants.get(userId);
- if (targetAppList == null) {
- return; // no grants for this user
- }
- for (int i = targetAppList.size() - 1; i >= 0; --i) {
- targetAppList.valueAt(i).delete(instantAppId);
+ // remove any grants
+ if (mInstantGrants == null) {
+ return; // no grants on the system
+ }
+ final WatchedSparseArray<WatchedSparseBooleanArray> targetAppList =
+ mInstantGrants.get(userId);
+ if (targetAppList == null) {
+ return; // no grants for this user
+ }
+ for (int i = targetAppList.size() - 1; i >= 0; --i) {
+ targetAppList.valueAt(i).delete(instantAppId);
+ }
+ } finally {
+ onChanged();
}
}
@@ -487,11 +547,13 @@
if (mInstantGrants == null) {
return; // no grants on the system
}
- final SparseArray<SparseBooleanArray> targetAppList = mInstantGrants.get(userId);
+ final WatchedSparseArray<WatchedSparseBooleanArray> targetAppList =
+ mInstantGrants.get(userId);
if (targetAppList == null) {
return; // no grants for this user
}
targetAppList.delete(targetAppId);
+ onChanged();
}
@GuardedBy("mService.mLock")
@@ -502,9 +564,6 @@
if (uninstalledApp == null) {
return;
}
- if (mUninstalledInstantApps == null) {
- mUninstalledInstantApps = new SparseArray<>();
- }
List<UninstalledInstantAppState> uninstalledAppStates =
mUninstalledInstantApps.get(userId);
if (uninstalledAppStates == null) {
@@ -593,9 +652,7 @@
uninstalledAppStates.remove(i);
if (uninstalledAppStates.isEmpty()) {
mUninstalledInstantApps.remove(userId);
- if (mUninstalledInstantApps.size() <= 0) {
- mUninstalledInstantApps = null;
- }
+ onChanged();
return;
}
}
@@ -919,8 +976,7 @@
final long identity = Binder.clearCallingIdentity();
try {
for (String grantedPermission : appInfo.getGrantedPermissions()) {
- final boolean propagatePermission =
- mPermissionManager.canPropagatePermissionToInstantApp(grantedPermission);
+ final boolean propagatePermission = canPropagatePermission(grantedPermission);
if (propagatePermission && pkg.getRequestedPermissions().contains(
grantedPermission)) {
mService.grantRuntimePermission(pkg.getPackageName(), grantedPermission,
@@ -932,6 +988,19 @@
}
}
+ private boolean canPropagatePermission(@NonNull String permissionName) {
+ final PermissionManager permissionManager = mService.mContext.getSystemService(
+ PermissionManager.class);
+ final PermissionInfo permissionInfo = permissionManager.getPermissionInfo(permissionName,
+ 0);
+ return permissionInfo != null
+ && (permissionInfo.getProtection() == PermissionInfo.PROTECTION_DANGEROUS
+ || (permissionInfo.getProtectionFlags()
+ & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0)
+ && (permissionInfo.getProtectionFlags() & PermissionInfo.PROTECTION_FLAG_INSTANT)
+ != 0;
+ }
+
private @NonNull
InstantAppInfo peekOrParseUninstalledInstantAppInfo(
@NonNull String packageName, @UserIdInt int userId) {
@@ -994,12 +1063,7 @@
}
}
- if (uninstalledAppStates != null) {
- if (mUninstalledInstantApps == null) {
- mUninstalledInstantApps = new SparseArray<>();
- }
- mUninstalledInstantApps.put(userId, uninstalledAppStates);
- }
+ mUninstalledInstantApps.put(userId, uninstalledAppStates);
return uninstalledAppStates;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4cf9933..22f4a92 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -394,6 +394,7 @@
import com.android.server.storage.DeviceStorageMonitorInternal;
import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.utils.TimingsTraceAndSlog;
+import com.android.server.utils.WatchedArrayMap;
import com.android.server.wm.ActivityTaskManagerInternal;
import dalvik.system.CloseGuard;
@@ -1002,7 +1003,7 @@
Producer<PackageParser2> scanningPackageParserProducer,
Producer<PackageParser2> preparingPackageParserProducer,
Producer<PackageInstallerService> packageInstallerServiceProducer,
- ProducerWithArgument<InstantAppResolverConnection, ComponentName>
+ ProducerWithArgument<InstantAppResolverConnection, ComponentName>
instantAppResolverConnectionProducer,
Producer<ModuleInfoProvider> moduleInfoProviderProducer,
Producer<LegacyPermissionManagerInternal> legacyPermissionManagerInternalProducer,
@@ -3302,7 +3303,8 @@
// Clean up orphaned packages for which the code path doesn't exist
// and they are an update to a system app - caused by bug/32321269
- final ArrayMap<String, PackageSetting> packageSettings = mSettings.getPackagesLocked();
+ final WatchedArrayMap<String, PackageSetting> packageSettings =
+ mSettings.getPackagesLocked();
final int packageSettingCount = packageSettings.size();
for (int i = packageSettingCount - 1; i >= 0; i--) {
PackageSetting ps = packageSettings.valueAt(i);
@@ -4806,6 +4808,12 @@
enforceCrossUserPermission(Binder.getCallingUid(), userId,
false /* requireFullPermission */, false /* checkShell */, "get package info");
+ return getPackageInfoInternalBody(packageName, versionCode, flags, filterCallingUid,
+ userId);
+ }
+
+ private PackageInfo getPackageInfoInternalBody(String packageName, long versionCode,
+ int flags, int filterCallingUid, int userId) {
// reader
synchronized (mLock) {
// Normalize package name to handle renamed packages and static libs
@@ -5227,6 +5235,11 @@
"get application info");
}
+ return getApplicationInfoInternalBody(packageName, flags, filterCallingUid, userId);
+ }
+
+ private ApplicationInfo getApplicationInfoInternalBody(String packageName, int flags,
+ int filterCallingUid, int userId) {
// writer
synchronized (mLock) {
// Normalize package name to handle renamed packages and static libs
@@ -5659,6 +5672,11 @@
false /* requireFullPermission */, false /* checkShell */, "get activity info");
}
+ return getActivityInfoInternalBody(component, flags, filterCallingUid, userId);
+ }
+
+ private ActivityInfo getActivityInfoInternalBody(ComponentName component, int flags,
+ int filterCallingUid, int userId) {
synchronized (mLock) {
ParsedActivity a = mComponentResolver.getActivity(component);
@@ -5965,6 +5983,11 @@
flags = updateFlagsForComponent(flags, userId);
enforceCrossUserOrProfilePermission(callingUid, userId, false /* requireFullPermission */,
false /* checkShell */, "get service info");
+ return getServiceInfoBody(component, flags, userId, callingUid);
+ }
+
+ private ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId,
+ int callingUid) {
synchronized (mLock) {
ParsedService s = mComponentResolver.getService(component);
if (DEBUG_PACKAGE_INFO) Log.v(
@@ -6537,6 +6560,11 @@
final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
final int userId = UserHandle.getUserId(uid);
final int appId = UserHandle.getAppId(uid);
+ return getPackagesForUidInternalBody(callingUid, userId, appId, isCallerInstantApp);
+ }
+
+ private String[] getPackagesForUidInternalBody(int callingUid, int userId, int appId,
+ boolean isCallerInstantApp) {
// reader
synchronized (mLock) {
final Object obj = mSettings.getSettingLPr(appId);
@@ -6888,6 +6916,15 @@
}
// Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
// Or if there's already an ephemeral app installed that handles the action
+ return isInstantAppResolutionAllowedBody(intent, resolvedActivities, userId,
+ skipPackageCheck);
+ }
+
+ // Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
+ // Or if there's already an ephemeral app installed that handles the action
+ private boolean isInstantAppResolutionAllowedBody(
+ Intent intent, List<ResolveInfo> resolvedActivities, int userId,
+ boolean skipPackageCheck) {
synchronized (mLock) {
final int count = (resolvedActivities == null ? 0 : resolvedActivities.size());
for (int n = 0; n < count; n++) {
@@ -7457,6 +7494,23 @@
userId, false /*resolveForStart*/, true /*allowDynamicSplits*/);
}
+ // Collect the results of queryIntentActivitiesInternalBody into a single class
+ private static class QueryIntentActivitiesResult {
+ public boolean sortResult = false;
+ public boolean addInstant = false;
+ public List<ResolveInfo> result = null;
+ public List<ResolveInfo> answer = null;
+
+ QueryIntentActivitiesResult(List<ResolveInfo> l) {
+ answer = l;
+ }
+ QueryIntentActivitiesResult(boolean s, boolean a, List<ResolveInfo> l) {
+ sortResult = s;
+ addInstant = a;
+ result = l;
+ }
+ }
+
private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
String resolvedType, int flags, @PrivateResolveFlags int privateResolveFlags,
int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits) {
@@ -7530,11 +7584,37 @@
return result;
}
+ QueryIntentActivitiesResult lockedResult =
+ queryIntentActivitiesInternalBody(
+ intent, resolvedType, flags, filterCallingUid, userId, resolveForStart,
+ allowDynamicSplits, pkgName, instantAppPkgName);
+ if (lockedResult.answer != null) {
+ return lockedResult.answer;
+ }
+
+ if (lockedResult.addInstant) {
+ String callingPkgName = getInstantAppPackageName(filterCallingUid);
+ boolean isRequesterInstantApp = isInstantApp(callingPkgName, userId);
+ lockedResult.result = maybeAddInstantAppInstaller(lockedResult.result, intent,
+ resolvedType, flags, userId, resolveForStart, isRequesterInstantApp);
+ }
+ if (lockedResult.sortResult) {
+ Collections.sort(lockedResult.result, RESOLVE_PRIORITY_SORTER);
+ }
+ return applyPostResolutionFilter(
+ lockedResult.result, instantAppPkgName, allowDynamicSplits, filterCallingUid,
+ resolveForStart, userId, intent);
+ }
+
+ private @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
+ Intent intent, String resolvedType, int flags, int filterCallingUid, int userId,
+ boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
+ String instantAppPkgName) {
// reader
- boolean sortResult = false;
- boolean addInstant = false;
- List<ResolveInfo> result;
synchronized (mLock) {
+ boolean sortResult = false;
+ boolean addInstant = false;
+ List<ResolveInfo> result = null;
if (pkgName == null) {
List<CrossProfileIntentFilter> matchingFilters =
getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);
@@ -7544,9 +7624,11 @@
if (xpResolveInfo != null) {
List<ResolveInfo> xpResult = new ArrayList<>(1);
xpResult.add(xpResolveInfo);
- return applyPostResolutionFilter(
- filterIfNotSystemUser(xpResult, userId), instantAppPkgName,
- allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent);
+ return new QueryIntentActivitiesResult(
+ applyPostResolutionFilter(
+ filterIfNotSystemUser(xpResult, userId), instantAppPkgName,
+ allowDynamicSplits, filterCallingUid, resolveForStart, userId,
+ intent));
}
// Check for results in the current profile.
@@ -7585,17 +7667,19 @@
// And we are not going to add emphemeral app, so we can return the
// result straight away.
result.add(xpDomainInfo.resolveInfo);
- return applyPostResolutionFilter(result, instantAppPkgName,
- allowDynamicSplits, filterCallingUid, resolveForStart, userId,
- intent);
+ return new QueryIntentActivitiesResult(
+ applyPostResolutionFilter(result, instantAppPkgName,
+ allowDynamicSplits, filterCallingUid, resolveForStart,
+ userId, intent));
}
} else if (result.size() <= 1 && !addInstant) {
// No result in parent user and <= 1 result in current profile, and we
// are not going to add emphemeral app, so we can return the result without
// further processing.
- return applyPostResolutionFilter(result, instantAppPkgName,
+ return new QueryIntentActivitiesResult(
+ applyPostResolutionFilter(result, instantAppPkgName,
allowDynamicSplits, filterCallingUid, resolveForStart, userId,
- intent);
+ intent));
}
// We have more than one candidate (combining results from current and parent
// profile), so we need filtering and sorting.
@@ -7623,19 +7707,8 @@
}
}
}
+ return new QueryIntentActivitiesResult(sortResult, addInstant, result);
}
- if (addInstant) {
- String callingPkgName = getInstantAppPackageName(filterCallingUid);
- boolean isRequesterInstantApp = isInstantApp(callingPkgName, userId);
- result = maybeAddInstantAppInstaller(result, intent, resolvedType, flags, userId,
- resolveForStart, isRequesterInstantApp);
- }
- if (sortResult) {
- Collections.sort(result, RESOLVE_PRIORITY_SORTER);
- }
- return applyPostResolutionFilter(
- result, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart,
- userId, intent);
}
private List<ResolveInfo> maybeAddInstantAppInstaller(List<ResolveInfo> result, Intent intent,
@@ -7982,14 +8055,30 @@
candidates.size());
}
- final ArrayList<ResolveInfo> result = new ArrayList<>();
- final ArrayList<ResolveInfo> alwaysList = new ArrayList<>();
- final ArrayList<ResolveInfo> undefinedList = new ArrayList<>();
- final ArrayList<ResolveInfo> alwaysAskList = new ArrayList<>();
- final ArrayList<ResolveInfo> neverList = new ArrayList<>();
- final ArrayList<ResolveInfo> matchAllList = new ArrayList<>();
+ final ArrayList<ResolveInfo> result =
+ filterCandidatesWithDomainPreferredActivitiesLPrBody(
+ intent, matchFlags, candidates, xpDomainInfo, userId, debug);
+ if (DEBUG_PREFERRED || DEBUG_DOMAIN_VERIFICATION) {
+ Slog.v(TAG, "Filtered results with preferred activities. New candidates count: "
+ + result.size());
+ for (ResolveInfo info : result) {
+ Slog.v(TAG, " + " + info.activityInfo);
+ }
+ }
+ return result;
+ }
+
+ private ArrayList<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPrBody(
+ Intent intent, int matchFlags, List<ResolveInfo> candidates,
+ CrossProfileDomainInfo xpDomainInfo, int userId, boolean debug) {
synchronized (mLock) {
+ final ArrayList<ResolveInfo> result = new ArrayList<>();
+ final ArrayList<ResolveInfo> alwaysList = new ArrayList<>();
+ final ArrayList<ResolveInfo> undefinedList = new ArrayList<>();
+ final ArrayList<ResolveInfo> alwaysAskList = new ArrayList<>();
+ final ArrayList<ResolveInfo> neverList = new ArrayList<>();
+ final ArrayList<ResolveInfo> matchAllList = new ArrayList<>();
final int count = candidates.size();
// First, try to use linked apps. Partition the candidates into four lists:
// one for the final results, one for the "do not use ever", one for "undefined status"
@@ -8125,15 +8214,8 @@
result.removeAll(neverList);
}
}
+ return result;
}
- if (DEBUG_PREFERRED || DEBUG_DOMAIN_VERIFICATION) {
- Slog.v(TAG, "Filtered results with preferred activities. New candidates count: " +
- result.size());
- for (ResolveInfo info : result) {
- Slog.v(TAG, " + " + info.activityInfo);
- }
- }
- return result;
}
// Returns a packed value as a long:
@@ -8632,6 +8714,13 @@
return list;
}
+ return queryIntentServicesInternalBody(intent, resolvedType, flags,
+ userId, callingUid, instantAppPkgName);
+ }
+
+ private @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent,
+ String resolvedType, int flags, int userId, int callingUid,
+ String instantAppPkgName) {
// reader
synchronized (mLock) {
String pkgName = intent.getPackage();
@@ -8857,15 +8946,21 @@
}
if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList();
flags = updateFlagsForPackage(flags, userId);
- final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
- final boolean listApex = (flags & MATCH_APEX) != 0;
- final boolean listFactory = (flags & MATCH_FACTORY_ONLY) != 0;
enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
false /* checkShell */, "get installed packages");
+ return getInstalledPackagesBody(flags, userId, callingUid);
+ }
+
+ private ParceledListSlice<PackageInfo> getInstalledPackagesBody(int flags, int userId,
+ int callingUid) {
// writer
synchronized (mLock) {
+ final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
+ final boolean listApex = (flags & MATCH_APEX) != 0;
+ final boolean listFactory = (flags & MATCH_FACTORY_ONLY) != 0;
+
ArrayList<PackageInfo> list;
if (listUninstalled) {
list = new ArrayList<>(mSettings.getPackagesLocked().size());
@@ -9115,6 +9210,11 @@
if (HIDE_EPHEMERAL_APIS) {
return false;
}
+ return isInstantAppInternalBody(packageName, userId, callingUid);
+ }
+
+ private boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId,
+ int callingUid) {
synchronized (mLock) {
if (Process.isIsolated(callingUid)) {
callingUid = mIsolatedOwners.get(callingUid);
@@ -20813,8 +20913,12 @@
mSettings.applyDefaultPreferredAppsLPw(userId);
clearIntentFilterVerificationsLPw(userId);
primeDomainVerificationsLPw(userId);
+ final int numPackages = mPackages.size();
+ for (int i = 0; i < numPackages; i++) {
+ final AndroidPackage pkg = mPackages.valueAt(i);
+ mPermissionManager.resetRuntimePermissions(pkg, userId);
+ }
}
- mPermissionManager.resetAllRuntimePermissions(userId);
updateDefaultHomeNotLocked(userId);
// TODO: We have to reset the default SMS and Phone. This requires
// significant refactoring to keep all default apps in the package
@@ -22312,7 +22416,7 @@
mUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
- mPermissionManager.systemReady();
+ mPermissionManager.onSystemReady();
int[] grantPermissionsUserIds = EMPTY_INT_ARRAY;
for (int userId : UserManagerService.getInstance().getUserIds()) {
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index ac76cf7..67bd82b4 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -175,22 +175,27 @@
public void setInstallerPackageName(String packageName) {
installSource = installSource.setInstallerPackage(packageName);
+ onChanged();
}
public void setInstallSource(InstallSource installSource) {
this.installSource = Objects.requireNonNull(installSource);
+ onChanged();
}
void removeInstallerPackage(String packageName) {
installSource = installSource.removeInstallerPackage(packageName);
+ onChanged();
}
public void setIsOrphaned(boolean isOrphaned) {
installSource = installSource.setIsOrphaned(isOrphaned);
+ onChanged();
}
public void setVolumeUuid(String volumeUuid) {
this.volumeUuid = volumeUuid;
+ onChanged();
}
public String getVolumeUuid() {
@@ -199,10 +204,12 @@
public void setTimeStamp(long newStamp) {
timeStamp = newStamp;
+ onChanged();
}
public void setUpdateAvailable(boolean updateAvailable) {
this.updateAvailable = updateAvailable;
+ onChanged();
}
public boolean isUpdateAvailable() {
@@ -272,6 +279,7 @@
if (state == null) {
state = new PackageUserState();
mUserState.put(userId, state);
+ onChanged();
}
return state;
}
@@ -289,6 +297,7 @@
PackageUserState st = modifyUserState(userId);
st.enabled = state;
st.lastDisableAppCaller = callingPackage;
+ onChanged();
}
int getEnabled(int userId) {
@@ -434,6 +443,7 @@
}
existingUserState.suspendParams.put(suspendingPackage, newSuspendParams);
existingUserState.suspended = true;
+ onChanged();
}
void removeSuspension(String suspendingPackage, int userId) {
@@ -445,6 +455,7 @@
}
}
existingUserState.suspended = (existingUserState.suspendParams != null);
+ onChanged();
}
void removeSuspension(Predicate<String> suspendingPackagePredicate, int userId) {
@@ -461,6 +472,7 @@
}
}
existingUserState.suspended = (existingUserState.suspendParams != null);
+ onChanged();
}
public boolean getInstantApp(int userId) {
@@ -506,6 +518,7 @@
state.instantApp = instantApp;
state.virtualPreload = virtualPreload;
state.harmfulAppWarning = harmfulAppWarning;
+ onChanged();
}
void setUserState(int userId, PackageUserState otherState) {
@@ -547,11 +560,17 @@
PackageUserState modifyUserStateComponents(int userId, boolean disabled, boolean enabled) {
PackageUserState state = modifyUserState(userId);
+ boolean changed = false;
if (disabled && state.disabledComponents == null) {
state.disabledComponents = new ArraySet<String>(1);
+ changed = true;
}
if (enabled && state.enabledComponents == null) {
state.enabledComponents = new ArraySet<String>(1);
+ changed = true;
+ }
+ if (changed) {
+ onChanged();
}
return state;
}
@@ -603,6 +622,7 @@
void removeUser(int userId) {
mUserState.delete(userId);
+ onChanged();
}
public int[] getNotInstalledUserIds() {
@@ -630,6 +650,7 @@
void setIntentFilterVerificationInfo(IntentFilterVerificationInfo info) {
verificationInfo = info;
+ onChanged();
}
// Returns a packed value as a long:
@@ -648,6 +669,7 @@
state.domainVerificationStatus = status;
if (status == PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
state.appLinkGeneration = generation;
+ onChanged();
}
}
@@ -694,6 +716,7 @@
void setHarmfulAppWarning(int userId, String harmfulAppWarning) {
PackageUserState userState = modifyUserState(userId);
userState.harmfulAppWarning = harmfulAppWarning;
+ onChanged();
}
String getHarmfulAppWarning(int userId) {
@@ -838,6 +861,7 @@
for (int i = 0; i < other.mUserState.size(); i++) {
mUserState.put(other.mUserState.keyAt(i), other.mUserState.valueAt(i));
}
+ onChanged();
return this;
}
}
diff --git a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
index 08a87d8..d0f9787 100644
--- a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
+++ b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
@@ -19,10 +19,12 @@
import android.annotation.NonNull;
import android.content.IntentFilter;
-import com.android.server.IntentResolver;
+import com.android.server.utils.Snappable;
+import com.android.server.utils.WatchableIntentResolver;
public class PersistentPreferredIntentResolver
- extends IntentResolver<PersistentPreferredActivity, PersistentPreferredActivity> {
+ extends WatchableIntentResolver<PersistentPreferredActivity, PersistentPreferredActivity>
+ implements Snappable {
@Override
protected PersistentPreferredActivity[] newArray(int size) {
return new PersistentPreferredActivity[size];
@@ -37,4 +39,15 @@
protected boolean isPackageForFilter(String packageName, PersistentPreferredActivity filter) {
return packageName.equals(filter.mComponent.getPackageName());
}
+
+ /**
+ * Return a snapshot of the current object. The snapshot is a read-only copy suitable
+ * for read-only methods.
+ * @return A snapshot of the current object.
+ */
+ public PersistentPreferredIntentResolver snapshot() {
+ PersistentPreferredIntentResolver result = new PersistentPreferredIntentResolver();
+ result.doCopy(this);
+ return result;
+ }
}
diff --git a/services/core/java/com/android/server/pm/PreferredIntentResolver.java b/services/core/java/com/android/server/pm/PreferredIntentResolver.java
index ff3df13..b62421e 100644
--- a/services/core/java/com/android/server/pm/PreferredIntentResolver.java
+++ b/services/core/java/com/android/server/pm/PreferredIntentResolver.java
@@ -19,13 +19,15 @@
import android.annotation.NonNull;
import android.content.IntentFilter;
-import java.io.PrintWriter;
+import com.android.server.utils.Snappable;
+import com.android.server.utils.WatchableIntentResolver;
-import com.android.server.IntentResolver;
+import java.io.PrintWriter;
import java.util.ArrayList;
public class PreferredIntentResolver
- extends IntentResolver<PreferredActivity, PreferredActivity> {
+ extends WatchableIntentResolver<PreferredActivity, PreferredActivity>
+ implements Snappable {
@Override
protected PreferredActivity[] newArray(int size) {
return new PreferredActivity[size];
@@ -66,4 +68,15 @@
}
return true;
}
+
+ /**
+ * Return a snapshot of the current object. The snapshot is a read-only copy suitable
+ * for read-only methods.
+ * @return A snapshot of the current object.
+ */
+ public PreferredIntentResolver snapshot() {
+ PreferredIntentResolver result = new PreferredIntentResolver();
+ result.doCopy(this);
+ return result;
+ }
}
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index 968c4b5..7924d5d 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -16,17 +16,71 @@
package com.android.server.pm;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.pm.ApplicationInfo;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.pm.permission.LegacyPermissionState;
+import com.android.server.utils.Watchable;
+import com.android.server.utils.WatchableImpl;
+import com.android.server.utils.Watcher;
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-public abstract class SettingBase {
+public abstract class SettingBase implements Watchable {
+ // TODO: make this variable protected, or even private with a getter and setter.
+ // Simply making it protected or private requires that the name be changed to conformm
+ // to the Android naming convention, and that touches quite a few files.
int pkgFlags;
+
+ // TODO: make this variable protected, or even private with a getter and setter.
+ // Simply making it protected or private requires that the name be changed to conformm
+ // to the Android naming convention, and that touches quite a few files.
int pkgPrivateFlags;
/**
+ * Watchable machinery
+ */
+ private final Watchable mWatchable = new WatchableImpl();
+
+ /**
+ * Ensures an observer is in the list, exactly once. The observer cannot be null. The
+ * function quietly returns if the observer is already in the list.
+ *
+ * @param observer The {@link Watcher} to be notified when the {@link Watchable} changes.
+ */
+ public void registerObserver(@NonNull Watcher observer) {
+ mWatchable.registerObserver(observer);
+ }
+
+ /**
+ * Ensures an observer is not in the list. The observer must not be null. The function
+ * quietly returns if the objserver is not in the list.
+ *
+ * @param observer The {@link Watcher} that should not be in the notification list.
+ */
+ public void unregisterObserver(@NonNull Watcher observer) {
+ mWatchable.unregisterObserver(observer);
+ }
+
+ /**
+ * Invokes {@link Watcher#onChange} on each registered observer. The method can be called
+ * with the {@link Watchable} that generated the event. In a tree of {@link Watchable}s, this
+ * is generally the first (deepest) {@link Watchable} to detect a change.
+ *
+ * @param what The {@link Watchable} that generated the event.
+ */
+ public void dispatchChange(@Nullable Watchable what) {
+ mWatchable.dispatchChange(what);
+ }
+ /**
+ * Notify listeners that this object has changed.
+ */
+ protected void onChanged() {
+ dispatchChange(this);
+ }
+
+ /**
* The legacy permission state that is read from package settings persistence for migration.
* This state here can not reflect the current permission state and should not be used for
* purposes other than migration.
@@ -53,6 +107,7 @@
pkgFlags = orig.pkgFlags;
pkgPrivateFlags = orig.pkgPrivateFlags;
mLegacyPermissionsState.copyFrom(orig.mLegacyPermissionsState);
+ onChanged();
}
@Deprecated
@@ -64,6 +119,7 @@
this.pkgFlags = pkgFlags
& (ApplicationInfo.FLAG_SYSTEM
| ApplicationInfo.FLAG_EXTERNAL_STORAGE);
+ onChanged();
}
void setPrivateFlags(int pkgPrivateFlags) {
@@ -75,5 +131,6 @@
| ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT
| ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER
| ApplicationInfo.PRIVATE_FLAG_ODM);
+ onChanged();
}
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 7482ef45..7c4dade 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -114,7 +114,14 @@
import com.android.server.pm.permission.LegacyPermissionSettings;
import com.android.server.pm.permission.LegacyPermissionState;
import com.android.server.pm.permission.LegacyPermissionState.PermissionState;
+import com.android.server.utils.Snappable;
+import com.android.server.utils.Snapshots;
import com.android.server.utils.TimingsTraceAndSlog;
+import com.android.server.utils.Watchable;
+import com.android.server.utils.WatchableImpl;
+import com.android.server.utils.WatchedArrayMap;
+import com.android.server.utils.WatchedSparseArray;
+import com.android.server.utils.Watcher;
import libcore.io.IoUtils;
@@ -148,10 +155,58 @@
/**
* Holds information about dynamic settings.
*/
-public final class Settings {
+public final class Settings implements Watchable, Snappable {
private static final String TAG = "PackageSettings";
/**
+ * Cached snapshot
+ */
+ private volatile Settings mSnapshot = null;
+
+ /**
+ * Watchable machinery
+ */
+ private final WatchableImpl mWatchable = new WatchableImpl();
+
+ /**
+ * Ensures an observer is in the list, exactly once. The observer cannot be null. The
+ * function quietly returns if the observer is already in the list.
+ *
+ * @param observer The {@link Watcher} to be notified when the {@link Watchable} changes.
+ */
+ public void registerObserver(@NonNull Watcher observer) {
+ mWatchable.registerObserver(observer);
+ }
+
+ /**
+ * Ensures an observer is not in the list. The observer must not be null. The function
+ * quietly returns if the objserver is not in the list.
+ *
+ * @param observer The {@link Watcher} that should not be in the notification list.
+ */
+ public void unregisterObserver(@NonNull Watcher observer) {
+ mWatchable.unregisterObserver(observer);
+ }
+
+ /**
+ * Invokes {@link Watcher#onChange} on each registered observer. The method can be called
+ * with the {@link Watchable} that generated the event. In a tree of {@link Watchable}s, this
+ * is generally the first (deepest) {@link Watchable} to detect a change.
+ *
+ * @param what The {@link Watchable} that generated the event.
+ */
+ public void dispatchChange(@Nullable Watchable what) {
+ mSnapshot = null;
+ mWatchable.dispatchChange(what);
+ }
+ /**
+ * Notify listeners that this object has changed.
+ */
+ protected void onChanged() {
+ dispatchChange(this);
+ }
+
+ /**
* Current version of the package database. Set it to the latest version in
* the {@link DatabaseVersion} class below to ensure the database upgrade
* doesn't happen repeatedly.
@@ -296,7 +351,7 @@
/** Map from package name to settings */
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
- final ArrayMap<String, PackageSetting> mPackages = new ArrayMap<>();
+ final WatchedArrayMap<String, PackageSetting> mPackages = new WatchedArrayMap<>();
/**
* List of packages that were involved in installing other packages, i.e. are listed
@@ -368,21 +423,21 @@
// The user's preferred activities associated with particular intent
// filters.
- private final SparseArray<PreferredIntentResolver> mPreferredActivities =
- new SparseArray<PreferredIntentResolver>();
+ private final WatchedSparseArray<PreferredIntentResolver>
+ mPreferredActivities = new WatchedSparseArray<>();
// The persistent preferred activities of the user's profile/device owner
// associated with particular intent filters.
- private final SparseArray<PersistentPreferredIntentResolver> mPersistentPreferredActivities =
- new SparseArray<PersistentPreferredIntentResolver>();
+ private final WatchedSparseArray<PersistentPreferredIntentResolver>
+ mPersistentPreferredActivities = new WatchedSparseArray<>();
// For every user, it is used to find to which other users the intent can be forwarded.
- private final SparseArray<CrossProfileIntentResolver> mCrossProfileIntentResolvers =
- new SparseArray<CrossProfileIntentResolver>();
+ private final WatchedSparseArray<CrossProfileIntentResolver>
+ mCrossProfileIntentResolvers = new WatchedSparseArray<>();
final ArrayMap<String, SharedUserSetting> mSharedUsers = new ArrayMap<>();
- private final ArrayList<SettingBase> mAppIds = new ArrayList<>();
- private final SparseArray<SettingBase> mOtherAppIds = new SparseArray<>();
+ private final ArrayList<SettingBase> mAppIds;
+ private final SparseArray<SettingBase> mOtherAppIds;
// For reading/writing settings file.
private final ArrayList<Signature> mPastSignatures =
@@ -415,17 +470,30 @@
private final File mSystemDir;
- public final KeySetManagerService mKeySetManagerService = new KeySetManagerService(mPackages);
+ public final KeySetManagerService mKeySetManagerService =
+ new KeySetManagerService(mPackages.untrackedMap());
/** Settings and other information about permissions */
final LegacyPermissionSettings mPermissions;
private final LegacyPermissionDataProvider mPermissionDataProvider;
+ /**
+ * The observer that watches for changes from array members
+ */
+ private final Watcher mObserver = new Watcher() {
+ @Override
+ public void onChange(@Nullable Watchable what) {
+ Settings.this.dispatchChange(what);
+ }
+ };
+
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
public Settings(Map<String, PackageSetting> pkgSettings) {
mLock = new Object();
mPackages.putAll(pkgSettings);
+ mAppIds = new ArrayList<>();
+ mOtherAppIds = new SparseArray<>();
mSystemDir = null;
mPermissions = null;
mRuntimePermissionsPersistence = null;
@@ -436,11 +504,17 @@
mStoppedPackagesFilename = null;
mBackupStoppedPackagesFilename = null;
mKernelMappingFilename = null;
+ mPackages.registerObserver(mObserver);
+ mPreferredActivities.registerObserver(mObserver);
+ mPersistentPreferredActivities.registerObserver(mObserver);
+ mCrossProfileIntentResolvers.registerObserver(mObserver);
}
Settings(File dataDir, RuntimePermissionsPersistence runtimePermissionsPersistence,
LegacyPermissionDataProvider permissionDataProvider, Object lock) {
mLock = lock;
+ mAppIds = new ArrayList<>();
+ mOtherAppIds = new SparseArray<>();
mPermissions = new LegacyPermissionSettings(lock);
mRuntimePermissionsPersistence = new RuntimePermissionPersistence(
runtimePermissionsPersistence);
@@ -463,18 +537,91 @@
// Deprecated: Needed for migration
mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
+ mPackages.registerObserver(mObserver);
+ mPreferredActivities.registerObserver(mObserver);
+ mPersistentPreferredActivities.registerObserver(mObserver);
+ mCrossProfileIntentResolvers.registerObserver(mObserver);
}
- private static void invalidatePackageCache() {
+ /**
+ * A copy constructor used in snapshot(). Attributes that are supposed to be
+ * immutable in the PackageManagerService application are referenced. Attributes that
+ * are changed by PackageManagerService APIs are deep-copied
+ */
+ private Settings(Settings r) {
+ final int mPackagesSize = r.mPackages.size();
+ mPackages.putAll(r.mPackages);
+
+ // The following assignments satisfy Java requirements but are not
+ // needed by the read-only methods. Note especially that the lock
+ // is not required because this clone is meant to support lock-free
+ // read-only methods.
+ mLock = null;
+ mRuntimePermissionsPersistence = r.mRuntimePermissionsPersistence;
+ mSettingsFilename = null;
+ mBackupSettingsFilename = null;
+ mPackageListFilename = null;
+ mStoppedPackagesFilename = null;
+ mBackupStoppedPackagesFilename = null;
+ mKernelMappingFilename = null;
+
+ mInstallerPackages.addAll(r.mInstallerPackages);
+ mKernelMapping.putAll(r.mKernelMapping);
+ mDisabledSysPackages.putAll(r.mDisabledSysPackages);
+ Snapshots.copy(mBlockUninstallPackages, r.mBlockUninstallPackages);
+ mRestoredIntentFilterVerifications.putAll(r.mRestoredIntentFilterVerifications);
+ mVersion.putAll(r.mVersion);
+ mVerifierDeviceIdentity = r.mVerifierDeviceIdentity;
+ WatchedSparseArray.snapshot(
+ mPreferredActivities, r.mPreferredActivities);
+ WatchedSparseArray.snapshot(
+ mPersistentPreferredActivities, r.mPersistentPreferredActivities);
+ WatchedSparseArray.snapshot(
+ mCrossProfileIntentResolvers, r.mCrossProfileIntentResolvers);
+ mSharedUsers.putAll(r.mSharedUsers);
+ mAppIds = new ArrayList<>(r.mAppIds);
+ mOtherAppIds = r.mOtherAppIds.clone();
+ mPastSignatures.addAll(r.mPastSignatures);
+ mKeySetRefs.putAll(r.mKeySetRefs);
+ mRenamedPackages.putAll(r.mRenamedPackages);
+ Snapshots.copy(mDefaultBrowserApp, r.mDefaultBrowserApp);
+ Snapshots.snapshot(mNextAppLinkGeneration, r.mNextAppLinkGeneration);
+ // mReadMessages
+ mPendingPackages.addAll(r.mPendingPackages);
+ mSystemDir = null;
+ // mKeySetManagerService;
+ mPermissions = r.mPermissions;
+ mPermissionDataProvider = r.mPermissionDataProvider;
+
+ // Do not register any Watchables
+ }
+
+ /**
+ * Return a snapshot. If the cached snapshot is null, build a new one. The logic in
+ * the function ensures that this function returns a valid snapshot even if a race
+ * condition causes the cached snapshot to be cleared asynchronously to this method.
+ */
+ public Settings snapshot() {
+ Settings s = mSnapshot;
+ if (s == null) {
+ s = new Settings(this);
+ s.mWatchable.seal();
+ mSnapshot = s;
+ }
+ return s;
+ }
+
+ private void invalidatePackageCache() {
PackageManagerService.invalidatePackageInfoCache();
ChangeIdStateCache.invalidate();
+ onChanged();
}
PackageSetting getPackageLPr(String pkgName) {
return mPackages.get(pkgName);
}
- ArrayMap<String, PackageSetting> getPackagesLocked() {
+ WatchedArrayMap<String, PackageSetting> getPackagesLocked() {
return mPackages;
}
@@ -5558,6 +5705,7 @@
/** This method takes a specific user id as well as UserHandle.USER_ALL. */
void clearPackagePreferredActivities(String packageName,
@NonNull SparseBooleanArray outUserChanged, int userId) {
+ boolean changed = false;
ArrayList<PreferredActivity> removed = null;
for (int i = 0; i < mPreferredActivities.size(); i++) {
final int thisUserId = mPreferredActivities.keyAt(i);
@@ -5585,8 +5733,12 @@
pir.removeFilter(pa);
}
outUserChanged.put(thisUserId, true);
+ changed = true;
}
}
+ if (changed) {
+ onChanged();
+ }
}
boolean clearPackagePersistentPreferredActivities(String packageName, int userId) {
@@ -5617,6 +5769,9 @@
changed = true;
}
}
+ if (changed) {
+ onChanged();
+ }
return changed;
}
@@ -5649,6 +5804,7 @@
changed.add(mPreferredActivities.keyAt(i));
}
}
+ onChanged();
return changed;
}
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 6103f558..9b1c08d 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -93,6 +93,7 @@
proc.addStateFrom(newProc);
}
}
+ onChanged();
}
}
@@ -117,6 +118,7 @@
}
// recalculate processes.
updateProcesses();
+ onChanged();
return true;
}
@@ -129,6 +131,7 @@
if (packages.add(packageSetting)) {
setFlags(this.pkgFlags | packageSetting.pkgFlags);
setPrivateFlags(this.pkgPrivateFlags | packageSetting.pkgPrivateFlags);
+ onChanged();
}
if (packageSetting.pkg != null) {
addProcesses(packageSetting.pkg.getProcesses());
@@ -169,6 +172,7 @@
}
if (ps.pkg.getTargetSdkVersion() < seInfoTargetSdkVersion) {
seInfoTargetSdkVersion = ps.pkg.getTargetSdkVersion();
+ onChanged();
}
}
@@ -179,6 +183,7 @@
final boolean isPrivileged = isPrivileged() | ps.pkg.isPrivileged();
ps.getPkgState().setOverrideSeInfo(SELinuxMMAC.getSeInfo(ps.pkg, isPrivileged,
seInfoTargetSdkVersion));
+ onChanged();
}
}
@@ -234,6 +239,7 @@
} else {
this.processes = null;
}
+ onChanged();
return this;
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 56fb5e8..95ce140 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -2739,7 +2739,8 @@
// Default launcher from role manager.
final long startGetHomeRoleHoldersAsUser = getStatStartTime();
- final String defaultLauncher = injectGetHomeRoleHolderAsUser(userId);
+ final String defaultLauncher = injectGetHomeRoleHolderAsUser(
+ getParentOrSelfUserId(userId));
logDurationStat(Stats.GET_DEFAULT_HOME, startGetHomeRoleHoldersAsUser);
if (defaultLauncher != null) {
@@ -4694,7 +4695,7 @@
final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
// Default launcher from package manager.
final ComponentName defaultLauncher = mPackageManagerInternal
- .getHomeActivitiesAsUser(allHomeCandidates, mUserId);
+ .getHomeActivitiesAsUser(allHomeCandidates, getParentOrSelfUserId(mUserId));
getOutPrintWriter().println("Launcher: " + defaultLauncher);
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 225c998..ccbf73c 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -4760,31 +4760,13 @@
final boolean hasParent = user.profileGroupId != user.id
&& user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID;
if (verbose) {
- final DevicePolicyManagerInternal dpm = getDevicePolicyManagerInternal();
- String deviceOwner = "";
- String profileOwner = "";
- if (dpm != null) {
- final long ident = Binder.clearCallingIdentity();
- try {
- if (dpm.getDeviceOwnerUserId() == user.id) {
- deviceOwner = " (device-owner)";
- }
- if (dpm.getProfileOwnerAsUser(user.id) != null) {
- profileOwner = " (profile-owner)";
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- pw.printf("%d: id=%d, name=%s, flags=%s%s%s%s%s%s%s%s%s\n", i, user.id,
- user.name,
+ pw.printf("%d: id=%d, name=%s, flags=%s%s%s%s%s%s%s\n", i, user.id, user.name,
UserInfo.flagsToString(user.flags),
hasParent ? " (parentId=" + user.profileGroupId + ")" : "",
running ? " (running)" : "",
user.partial ? " (partial)" : "",
user.preCreated ? " (pre-created)" : "",
user.convertedFromPreCreated ? " (converted)" : "",
- deviceOwner, profileOwner,
current ? " (current)" : "");
} else {
// NOTE: the standard "list users" command is used by integration tests and
@@ -4878,21 +4860,6 @@
if (userInfo.convertedFromPreCreated) {
pw.print(" <converted>");
}
- final DevicePolicyManagerInternal dpm = getDevicePolicyManagerInternal();
- if (dpm != null) {
- final long ident = Binder.clearCallingIdentity();
- try {
- if (dpm.getDeviceOwnerUserId() == userId) {
- pw.print(" <device-owner>");
- }
- if (dpm.getProfileOwnerAsUser(userId) != null) {
- pw.print(" <profile-owner>");
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
pw.println();
pw.print(" Type: "); pw.println(userInfo.userType);
pw.print(" Flags: "); pw.print(userInfo.flags); pw.print(" (");
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 1dbf839..2107536f 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1117,8 +1117,9 @@
mOnPermissionChangeListeners.removeListener(listener);
}
+ @Nullable
@Override
- @Nullable public List<String> getWhitelistedRestrictedPermissions(@NonNull String packageName,
+ public List<String> getAllowlistedRestrictedPermissions(@NonNull String packageName,
@PermissionWhitelistFlags int flags, @UserIdInt int userId) {
Objects.requireNonNull(packageName);
Preconditions.checkFlagsArgument(flags,
@@ -1131,7 +1132,7 @@
if (UserHandle.getCallingUserId() != userId) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS,
- "getWhitelistedRestrictedPermissions for user " + userId);
+ "getAllowlistedRestrictedPermissions for user " + userId);
}
final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
@@ -1217,7 +1218,7 @@
}
@Override
- public boolean addWhitelistedRestrictedPermission(@NonNull String packageName,
+ public boolean addAllowlistedRestrictedPermission(@NonNull String packageName,
@NonNull String permName, @PermissionWhitelistFlags int flags,
@UserIdInt int userId) {
// Other argument checks are done in get/setAllowlistedRestrictedPermissions
@@ -1228,7 +1229,7 @@
}
List<String> permissions =
- getWhitelistedRestrictedPermissions(packageName, flags, userId);
+ getAllowlistedRestrictedPermissions(packageName, flags, userId);
if (permissions == null) {
permissions = new ArrayList<>(1);
}
@@ -1255,14 +1256,14 @@
if (isImmutablyRestrictedPermission && mContext.checkCallingOrSelfPermission(
Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS)
!= PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Cannot modify whitelisting of an immutably "
+ throw new SecurityException("Cannot modify allowlisting of an immutably "
+ "restricted permission: " + permName);
}
return true;
}
@Override
- public boolean removeWhitelistedRestrictedPermission(@NonNull String packageName,
+ public boolean removeAllowlistedRestrictedPermission(@NonNull String packageName,
@NonNull String permName, @PermissionWhitelistFlags int flags,
@UserIdInt int userId) {
// Other argument checks are done in get/setAllowlistedRestrictedPermissions
@@ -1273,7 +1274,7 @@
}
final List<String> permissions =
- getWhitelistedRestrictedPermissions(packageName, flags, userId);
+ getAllowlistedRestrictedPermissions(packageName, flags, userId);
if (permissions != null && permissions.remove(permName)) {
return setAllowlistedRestrictedPermissions(packageName, permissions,
flags, userId);
@@ -1328,20 +1329,20 @@
+ " being installer on record or "
+ Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
}
- final List<String> whitelistedPermissions =
- getWhitelistedRestrictedPermissions(pkg.getPackageName(), flags, userId);
+ final List<String> allowlistedPermissions =
+ getAllowlistedRestrictedPermissions(pkg.getPackageName(), flags, userId);
if (permissions == null || permissions.isEmpty()) {
- if (whitelistedPermissions == null || whitelistedPermissions.isEmpty()) {
+ if (allowlistedPermissions == null || allowlistedPermissions.isEmpty()) {
return true;
}
} else {
// Only the system can add and remove while the installer can only remove.
final int permissionCount = permissions.size();
for (int i = 0; i < permissionCount; i++) {
- if ((whitelistedPermissions == null
- || !whitelistedPermissions.contains(permissions.get(i)))
+ if ((allowlistedPermissions == null
+ || !allowlistedPermissions.contains(permissions.get(i)))
&& !isCallerPrivileged) {
- throw new SecurityException("Adding to upgrade whitelist requires"
+ throw new SecurityException("Adding to upgrade allowlist requires"
+ Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
}
}
@@ -1349,7 +1350,7 @@
if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER) != 0) {
if (!isCallerPrivileged && !isCallerInstallerOnRecord) {
- throw new SecurityException("Modifying installer whitelist requires"
+ throw new SecurityException("Modifying installer allowlist requires"
+ " being installer on record or "
+ Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
}
@@ -1367,8 +1368,8 @@
}
@Override
- public boolean setAutoRevokeWhitelisted(
- @NonNull String packageName, boolean whitelisted, int userId) {
+ public boolean setAutoRevokeExempted(
+ @NonNull String packageName, boolean exempted, int userId) {
Objects.requireNonNull(packageName);
final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
@@ -1378,7 +1379,7 @@
return false;
}
- return setAutoRevokeExemptedInternal(pkg, whitelisted, userId);
+ return setAutoRevokeExemptedInternal(pkg, exempted, userId);
}
private boolean setAutoRevokeExemptedInternal(@NonNull AndroidPackage pkg, boolean exempted,
@@ -1386,7 +1387,7 @@
final int packageUid = UserHandle.getUid(userId, pkg.getUid());
if (mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_AUTO_REVOKE_MANAGED_BY_INSTALLER,
packageUid, pkg.getPackageName()) != MODE_ALLOWED) {
- // Whitelist user set - don't override
+ // Allowlist user set - don't override
return false;
}
@@ -1420,7 +1421,7 @@
}
@Override
- public boolean isAutoRevokeWhitelisted(@NonNull String packageName, int userId) {
+ public boolean isAutoRevokeExempted(@NonNull String packageName, int userId) {
Objects.requireNonNull(packageName);
final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
@@ -2872,7 +2873,7 @@
boolean softRestricted = bp.isSoftRestricted();
// If permission policy is not ready we don't deal with restricted
- // permissions as the policy may whitelist some permissions. Once
+ // permissions as the policy may allowlist some permissions. Once
// the policy is initialized we would re-evaluate permissions.
final boolean permissionPolicyInitialized =
isPermissionPolicyInitialized.get(userId);
@@ -3576,9 +3577,9 @@
if (isInSystemConfigPrivAppPermissions(pkg, permissionName)) {
return true;
}
- // Only enforce whitelist this on boot
+ // Only enforce the allowlist on boot
if (!mSystemReady
- // Updated system apps do not need to be whitelisted
+ // Updated system apps do not need to be allowlisted
&& !isUpdatedSystemApp) {
final ApexManager apexManager = ApexManager.getInstance();
final String packageName = pkg.getPackageName();
@@ -3587,7 +3588,7 @@
final boolean isInUpdatedApex = containingApexPackageName != null
&& !apexManager.isFactory(apexManager.getPackageInfo(containingApexPackageName,
MATCH_ACTIVE_PACKAGE));
- // Apps that are in updated apexs' do not need to be whitelisted
+ // Apps that are in updated apexs' do not need to be allowlisted
if (!isInUpdatedApex) {
// it's only a reportable violation if the permission isn't explicitly
// denied
@@ -3596,7 +3597,7 @@
}
Slog.w(TAG, "Privileged permission " + permissionName + " for package "
+ packageName + " (" + pkg.getPath()
- + ") not in privapp-permissions whitelist");
+ + ") not in privapp-permissions allowlist");
if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) {
synchronized (mLock) {
if (mPrivappPermissionsViolations == null) {
@@ -3775,10 +3776,10 @@
int newFlags = oldFlags;
int mask = 0;
- int whitelistFlagsCopy = allowlistFlags;
- while (whitelistFlagsCopy != 0) {
- final int flag = 1 << Integer.numberOfTrailingZeros(whitelistFlagsCopy);
- whitelistFlagsCopy &= ~flag;
+ int allowlistFlagsCopy = allowlistFlags;
+ while (allowlistFlagsCopy != 0) {
+ final int flag = 1 << Integer.numberOfTrailingZeros(allowlistFlagsCopy);
+ allowlistFlagsCopy &= ~flag;
switch (flag) {
case FLAG_PERMISSION_WHITELIST_SYSTEM: {
mask |= FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
@@ -3825,26 +3826,26 @@
updatePermissions = true;
- final boolean wasWhitelisted = (oldFlags
+ final boolean wasAllowlisted = (oldFlags
& (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0;
- final boolean isWhitelisted = (newFlags
+ final boolean isAllowlisted = (newFlags
& (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0;
// If the permission is policy fixed as granted but it is no longer
- // on any of the whitelists we need to clear the policy fixed flag
- // as whitelisting trumps policy i.e. policy cannot grant a non
+ // on any of the allowlists we need to clear the policy fixed flag
+ // as allowlisting trumps policy i.e. policy cannot grant a non
// grantable permission.
if ((oldFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
- if (!isWhitelisted && isGranted) {
+ if (!isAllowlisted && isGranted) {
mask |= PackageManager.FLAG_PERMISSION_POLICY_FIXED;
newFlags &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED;
}
}
- // If we are whitelisting an app that does not support runtime permissions
+ // If we are allowlisting an app that does not support runtime permissions
// we need to make sure it goes through the permission review UI at launch.
if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M
- && !wasWhitelisted && isWhitelisted) {
+ && !wasAllowlisted && isAllowlisted) {
mask |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
newFlags |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
}
@@ -3854,7 +3855,7 @@
}
if (updatePermissions) {
- // Update permission of this app to take into account the new whitelist state.
+ // Update permission of this app to take into account the new allowlist state.
restorePermissionState(pkg, false, pkg.getPackageName(), mDefaultPermissionCallback);
// If this resulted in losing a permission we need to kill the app.
@@ -4487,7 +4488,7 @@
synchronized (mLock) {
if (mPrivappPermissionsViolations != null) {
throw new IllegalStateException("Signature|privileged permissions not in "
- + "privapp-permissions whitelist: " + mPrivappPermissionsViolations);
+ + "privapp-permissions allowlist: " + mPrivappPermissionsViolations);
}
}
@@ -4868,13 +4869,6 @@
}
}
- private boolean canPropagatePermissionToInstantApp(@NonNull String permissionName) {
- synchronized (mLock) {
- final Permission bp = mRegistry.getPermission(permissionName);
- return bp != null && (bp.isRuntime() || bp.isDevelopment()) && bp.isInstant();
- }
- }
-
@NonNull
private List<LegacyPermission> getLegacyPermissions() {
synchronized (mLock) {
@@ -4954,7 +4948,7 @@
private class PermissionManagerServiceInternalImpl implements PermissionManagerServiceInternal {
@Override
- public void systemReady() {
+ public void onSystemReady() {
PermissionManagerService.this.systemReady();
}
@@ -5012,11 +5006,6 @@
Preconditions.checkArgumentNonNegative(userId, "userId");
resetRuntimePermissionsInternal(pkg, userId);
}
- @Override
- public void resetAllRuntimePermissions(@UserIdInt int userId) {
- Preconditions.checkArgumentNonNegative(userId, "userId");
- mPackageManagerInt.forEachPackage(pkg -> resetRuntimePermissionsInternal(pkg, userId));
- }
@Override
public Permission getPermissionTEMP(String permName) {
@@ -5157,11 +5146,6 @@
onPackageUninstalledInternal(packageName, appId, pkg, sharedUserPkgs, userId);
}
- @Override
- public boolean canPropagatePermissionToInstantApp(@NonNull String permissionName) {
- return PermissionManagerService.this.canPropagatePermissionToInstantApp(permissionName);
- }
-
@NonNull
@Override
public List<LegacyPermission> getLegacyPermissions() {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 0817d4f..1cfae00 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -54,8 +54,6 @@
void removeOnRuntimePermissionStateChangedListener(
@NonNull OnRuntimePermissionStateChangedListener listener);
- void systemReady();
-
/**
* Get whether permission review is required for a package.
*
@@ -94,14 +92,6 @@
@UserIdInt int userId);
/**
- * Reset the runtime permission state changes for all packages.
- *
- * @param userId the user ID
- */
- //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
- void resetAllRuntimePermissions(@UserIdInt int userId);
-
- /**
* Read legacy permission state from package settings.
*
* TODO(zhanghai): This is a temporary method because we should not expose
@@ -201,6 +191,12 @@
void writeLegacyPermissionsTEMP(@NonNull LegacyPermissionSettings legacyPermissionSettings);
/**
+ * Callback when the system is ready.
+ */
+ //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+ void onSystemReady();
+
+ /**
* Callback when a user has been created.
*
* @param userId the created user ID
@@ -265,14 +261,6 @@
@NonNull List<AndroidPackage> sharedUserPkgs, @UserIdInt int userId);
/**
- * Check whether a permission can be propagated to instant app.
- *
- * @param permissionName the name of the permission
- * @return whether the permission can be propagated
- */
- boolean canPropagatePermissionToInstantApp(@NonNull String permissionName);
-
- /**
* Listener for package permission state (permissions or flags) changes.
*/
interface OnRuntimePermissionStateChangedListener {
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java b/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java
index 88e5f69..79c0392 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java
@@ -16,7 +16,11 @@
package com.android.server.powerstats;
+import android.hardware.power.stats.ChannelInfo;
+import android.hardware.power.stats.EnergyMeasurement;
import android.hardware.power.stats.IPowerStats;
+import android.hardware.power.stats.PowerEntityInfo;
+import android.hardware.power.stats.StateResidencyResult;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
@@ -32,6 +36,7 @@
*/
public final class PowerStatsHALWrapper {
private static final String TAG = PowerStatsHALWrapper.class.getSimpleName();
+ private static final boolean DEBUG = false;
/**
* IPowerStatsHALWrapper defines the interface to the PowerStatsHAL.
@@ -122,17 +127,30 @@
*
* @return true if connection to power stats HAL was correctly established.
*/
- boolean initialize();
+ boolean isInitialized();
}
/**
- * PowerStatsHALWrapperImpl is the implementation of the IPowerStatsHALWrapper
- * used by the PowerStatsService. Other implementations will be used by the testing
- * framework and will be passed into the PowerStatsService through an injector.
+ * PowerStatsHALWrapper20Impl is the implementation of the IPowerStatsHALWrapper
+ * used by the PowerStatsService on devices that support only PowerStats HAL 2.0.
+ * Other implementations will be used by the testing framework and will be passed
+ * into the PowerStatsService through an injector.
*/
- public static final class PowerStatsHALWrapperImpl implements IPowerStatsHALWrapper {
+ public static final class PowerStatsHAL20WrapperImpl implements IPowerStatsHALWrapper {
private static Supplier<IPowerStats> sVintfPowerStats;
+ public PowerStatsHAL20WrapperImpl() {
+ Supplier<IPowerStats> service = new VintfHalCache();
+ sVintfPowerStats = null;
+
+ if (service.get() == null) {
+ if (DEBUG) Slog.d(TAG, "PowerStats HAL 2.0 not available on this device.");
+ sVintfPowerStats = null;
+ } else {
+ sVintfPowerStats = service;
+ }
+ }
+
@Override
public android.hardware.power.stats.PowerEntityInfo[] getPowerEntityInfo() {
android.hardware.power.stats.PowerEntityInfo[] powerEntityInfoHAL = null;
@@ -141,7 +159,7 @@
try {
powerEntityInfoHAL = sVintfPowerStats.get().getPowerEntityInfo();
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to get power entity info from PowerStats HAL");
+ if (DEBUG) Slog.d(TAG, "Failed to get power entity info from PowerStats HAL");
}
}
@@ -158,7 +176,7 @@
stateResidencyResultHAL =
sVintfPowerStats.get().getStateResidency(powerEntityIds);
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to get state residency from PowerStats HAL");
+ if (DEBUG) Slog.d(TAG, "Failed to get state residency from PowerStats HAL");
}
}
@@ -173,7 +191,9 @@
try {
energyConsumerInfoHAL = sVintfPowerStats.get().getEnergyConsumerInfo();
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to get energy consumer info from PowerStats HAL");
+ if (DEBUG) {
+ Slog.d(TAG, "Failed to get energy consumer info from PowerStats HAL");
+ }
}
}
@@ -190,7 +210,9 @@
energyConsumedHAL =
sVintfPowerStats.get().getEnergyConsumed(energyConsumerIds);
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to get energy consumer results from PowerStats HAL");
+ if (DEBUG) {
+ Slog.d(TAG, "Failed to get energy consumer results from PowerStats HAL");
+ }
}
}
@@ -205,7 +227,7 @@
try {
energyMeterInfoHAL = sVintfPowerStats.get().getEnergyMeterInfo();
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to get energy meter info from PowerStats HAL");
+ if (DEBUG) Slog.d(TAG, "Failed to get energy meter info from PowerStats HAL");
}
}
@@ -221,7 +243,7 @@
energyMeasurementHAL =
sVintfPowerStats.get().readEnergyMeters(channelIds);
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to get energy measurements from PowerStats HAL");
+ if (DEBUG) Slog.d(TAG, "Failed to get energy measurements from PowerStats HAL");
}
}
@@ -229,17 +251,90 @@
}
@Override
- public boolean initialize() {
- Supplier<IPowerStats> service = new VintfHalCache();
+ public boolean isInitialized() {
+ return (sVintfPowerStats != null);
+ }
+ }
- if (service.get() == null) {
- sVintfPowerStats = null;
- return false;
+ /**
+ * PowerStatsHALWrapper10Impl is the implementation of the IPowerStatsHALWrapper
+ * used by the PowerStatsService on devices that support only PowerStats HAL 1.0.
+ * Other implementations will be used by the testing framework and will be passed
+ * into the PowerStatsService through an injector.
+ */
+ public static final class PowerStatsHAL10WrapperImpl implements IPowerStatsHALWrapper {
+ private boolean mIsInitialized;
+
+ // PowerStatsHAL 1.0 native functions exposed by JNI layer.
+ private static native boolean nativeInit();
+ private static native PowerEntityInfo[] nativeGetPowerEntityInfo();
+ private static native StateResidencyResult[] nativeGetStateResidency(int[] powerEntityIds);
+ private static native ChannelInfo[] nativeGetEnergyMeterInfo();
+ private static native EnergyMeasurement[] nativeReadEnergyMeters(int[] channelIds);
+
+ public PowerStatsHAL10WrapperImpl() {
+ if (nativeInit()) {
+ mIsInitialized = true;
} else {
- sVintfPowerStats = service;
- return true;
+ if (DEBUG) Slog.d(TAG, "PowerStats HAL 1.0 not available on this device.");
+ mIsInitialized = false;
}
}
+
+ @Override
+ public android.hardware.power.stats.PowerEntityInfo[] getPowerEntityInfo() {
+ return nativeGetPowerEntityInfo();
+ }
+
+ @Override
+ public android.hardware.power.stats.StateResidencyResult[] getStateResidency(
+ int[] powerEntityIds) {
+ return nativeGetStateResidency(powerEntityIds);
+ }
+
+ @Override
+ public int[] getEnergyConsumerInfo() {
+ if (DEBUG) Slog.d(TAG, "Energy consumer info is not supported");
+ return null;
+ }
+
+ @Override
+ public android.hardware.power.stats.EnergyConsumerResult[] getEnergyConsumed(
+ int[] energyConsumerIds) {
+ if (DEBUG) Slog.d(TAG, "Energy consumer results are not supported");
+ return null;
+ }
+
+ @Override
+ public android.hardware.power.stats.ChannelInfo[] getEnergyMeterInfo() {
+ return nativeGetEnergyMeterInfo();
+ }
+
+ @Override
+ public android.hardware.power.stats.EnergyMeasurement[] readEnergyMeters(int[] channelIds) {
+ return nativeReadEnergyMeters(channelIds);
+ }
+
+ @Override
+ public boolean isInitialized() {
+ return mIsInitialized;
+ }
+ }
+
+ /**
+ * Returns an instance of an IPowerStatsHALWrapper. If PowerStats HAL 2.0 is supported on the
+ * device, return a PowerStatsHAL20WrapperImpl, else return a PowerStatsHAL10WrapperImpl.
+ *
+ * @return an instance of an IPowerStatsHALWrapper where preference is given to PowerStats HAL
+ * 2.0.
+ */
+ public static IPowerStatsHALWrapper getPowerStatsHalImpl() {
+ PowerStatsHAL20WrapperImpl powerStatsHAL20WrapperImpl = new PowerStatsHAL20WrapperImpl();
+ if (powerStatsHAL20WrapperImpl.isInitialized()) {
+ return powerStatsHAL20WrapperImpl;
+ } else {
+ return new PowerStatsHAL10WrapperImpl();
+ }
}
private static class VintfHalCache implements Supplier<IPowerStats>, IBinder.DeathRecipient {
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsService.java b/services/core/java/com/android/server/powerstats/PowerStatsService.java
index 1150d4b..ce50e583 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsService.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsService.java
@@ -29,7 +29,6 @@
import com.android.internal.util.DumpUtils;
import com.android.server.SystemService;
import com.android.server.powerstats.PowerStatsHALWrapper.IPowerStatsHALWrapper;
-import com.android.server.powerstats.PowerStatsHALWrapper.PowerStatsHALWrapperImpl;
import com.android.server.powerstats.ProtoStreamUtils.ChannelInfoUtils;
import com.android.server.powerstats.ProtoStreamUtils.EnergyConsumerIdUtils;
import com.android.server.powerstats.ProtoStreamUtils.PowerEntityInfoUtils;
@@ -78,7 +77,7 @@
}
IPowerStatsHALWrapper createPowerStatsHALWrapperImpl() {
- return new PowerStatsHALWrapperImpl();
+ return PowerStatsHALWrapper.getPowerStatsHalImpl();
}
PowerStatsLogger createPowerStatsLogger(Context context, File dataStoragePath,
@@ -143,7 +142,7 @@
private void onSystemServiceReady() {
mPowerStatsHALWrapper = mInjector.createPowerStatsHALWrapperImpl();
- if (mPowerStatsHALWrapper.initialize()) {
+ if (mPowerStatsHALWrapper.isInitialized()) {
if (DEBUG) Slog.d(TAG, "Starting PowerStatsService");
// Only start logger and triggers if initialization is successful.
diff --git a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
index 5a4256a..5e23b86 100644
--- a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
+++ b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
@@ -46,23 +46,31 @@
static class PowerEntityInfoUtils {
public static void print(PowerEntityInfo[] powerEntityInfo) {
+ if (powerEntityInfo == null) return;
+
for (int i = 0; i < powerEntityInfo.length; i++) {
Slog.d(TAG, "PowerEntityId: " + powerEntityInfo[i].powerEntityId
+ ", PowerEntityName: " + powerEntityInfo[i].powerEntityName);
- for (int j = 0; j < powerEntityInfo[i].states.length; j++) {
- Slog.d(TAG, " StateId: " + powerEntityInfo[i].states[j].stateId
- + ", StateName: " + powerEntityInfo[i].states[j].stateName);
+ if (powerEntityInfo[i].states != null) {
+ for (int j = 0; j < powerEntityInfo[i].states.length; j++) {
+ Slog.d(TAG, " StateId: " + powerEntityInfo[i].states[j].stateId
+ + ", StateName: " + powerEntityInfo[i].states[j].stateName);
+ }
}
}
}
public static void dumpsys(PowerEntityInfo[] powerEntityInfo, PrintWriter pw) {
+ if (powerEntityInfo == null) return;
+
for (int i = 0; i < powerEntityInfo.length; i++) {
pw.println("PowerEntityId: " + powerEntityInfo[i].powerEntityId
+ ", PowerEntityName: " + powerEntityInfo[i].powerEntityName);
- for (int j = 0; j < powerEntityInfo[i].states.length; j++) {
- pw.println(" StateId: " + powerEntityInfo[i].states[j].stateId
- + ", StateName: " + powerEntityInfo[i].states[j].stateName);
+ if (powerEntityInfo[i].states != null) {
+ for (int j = 0; j < powerEntityInfo[i].states.length; j++) {
+ pw.println(" StateId: " + powerEntityInfo[i].states[j].stateId
+ + ", StateName: " + powerEntityInfo[i].states[j].stateName);
+ }
}
}
}
@@ -70,6 +78,8 @@
static class StateResidencyResultUtils {
public static void print(StateResidencyResult[] stateResidencyResult) {
+ if (stateResidencyResult == null) return;
+
for (int i = 0; i < stateResidencyResult.length; i++) {
Slog.d(TAG, "PowerEntityId: " + stateResidencyResult[i].powerEntityId);
for (int j = 0; j < stateResidencyResult[i].stateResidencyData.length; j++) {
@@ -90,6 +100,8 @@
public static void packProtoMessage(ChannelInfo[] channelInfo, ProtoOutputStream pos) {
long token;
+ if (channelInfo == null) return;
+
for (int i = 0; i < channelInfo.length; i++) {
token = pos.start(PowerStatsServiceMeterProto.CHANNEL_INFO);
pos.write(ChannelInfoProto.CHANNEL_ID, channelInfo[i].channelId);
@@ -100,6 +112,8 @@
}
public static void print(ChannelInfo[] channelInfo) {
+ if (channelInfo == null) return;
+
for (int i = 0; i < channelInfo.length; i++) {
Slog.d(TAG, "ChannelId: " + channelInfo[i].channelId
+ ", ChannelName: " + channelInfo[i].channelName);
@@ -107,6 +121,8 @@
}
public static void dumpsys(ChannelInfo[] channelInfo, PrintWriter pw) {
+ if (channelInfo == null) return;
+
for (int i = 0; i < channelInfo.length; i++) {
pw.println("ChannelId: " + channelInfo[i].channelId
+ ", ChannelName: " + channelInfo[i].channelName);
@@ -125,6 +141,8 @@
ProtoOutputStream pos) {
long token;
+ if (energyMeasurement == null) return;
+
for (int i = 0; i < energyMeasurement.length; i++) {
token = pos.start(PowerStatsServiceMeterProto.ENERGY_MEASUREMENT);
pos.write(EnergyMeasurementProto.CHANNEL_ID, energyMeasurement[i].channelId);
@@ -200,6 +218,8 @@
}
public static void print(EnergyMeasurement[] energyMeasurement) {
+ if (energyMeasurement == null) return;
+
for (int i = 0; i < energyMeasurement.length; i++) {
Slog.d(TAG, "ChannelId: " + energyMeasurement[i].channelId
+ ", Timestamp (ms): " + energyMeasurement[i].timestampMs
@@ -212,6 +232,8 @@
public static void packProtoMessage(int[] energyConsumerId, ProtoOutputStream pos) {
long token;
+ if (energyConsumerId == null) return;
+
for (int i = 0; i < energyConsumerId.length; i++) {
token = pos.start(PowerStatsServiceModelProto.ENERGY_CONSUMER_ID);
pos.write(EnergyConsumerIdProto.ENERGY_CONSUMER_ID, energyConsumerId[i]);
@@ -220,12 +242,16 @@
}
public static void print(int[] energyConsumerId) {
+ if (energyConsumerId == null) return;
+
for (int i = 0; i < energyConsumerId.length; i++) {
Slog.d(TAG, "EnergyConsumerId: " + energyConsumerId[i]);
}
}
public static void dumpsys(int[] energyConsumerId, PrintWriter pw) {
+ if (energyConsumerId == null) return;
+
for (int i = 0; i < energyConsumerId.length; i++) {
pw.println("EnergyConsumerId: " + energyConsumerId[i]);
}
@@ -243,6 +269,8 @@
ProtoOutputStream pos) {
long token;
+ if (energyConsumerResult == null) return;
+
for (int i = 0; i < energyConsumerResult.length; i++) {
token = pos.start(PowerStatsServiceModelProto.ENERGY_CONSUMER_RESULT);
pos.write(EnergyConsumerResultProto.ENERGY_CONSUMER_ID,
@@ -321,6 +349,8 @@
}
public static void print(EnergyConsumerResult[] energyConsumerResult) {
+ if (energyConsumerResult == null) return;
+
for (int i = 0; i < energyConsumerResult.length; i++) {
Slog.d(TAG, "EnergyConsumerId: " + energyConsumerResult[i].energyConsumerId
+ ", Timestamp (ms): " + energyConsumerResult[i].timestampMs
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index 990055e..5c01e43 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -32,6 +32,8 @@
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.SystemProperties;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -49,10 +51,6 @@
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
/**
* The recovery system service is responsible for coordinating recovery related
@@ -84,9 +82,9 @@
private final Context mContext;
@GuardedBy("this")
- private final Map<String, IntentSender> mCallerPendingRequest = new HashMap<>();
+ private final ArrayMap<String, IntentSender> mCallerPendingRequest = new ArrayMap<>();
@GuardedBy("this")
- private final Set<String> mCallerPreparedForReboot = new HashSet<>();
+ private final ArraySet<String> mCallerPreparedForReboot = new ArraySet<>();
/**
* Need to prepare for resume on reboot.
@@ -121,7 +119,7 @@
@IntDef({ ROR_NEED_PREPARATION,
ROR_SKIP_PREPARATION_AND_NOTIFY,
ROR_SKIP_PREPARATION_NOT_NOTIFY })
- @interface ResumeOnRebootActionsOnRequest {}
+ private @interface ResumeOnRebootActionsOnRequest {}
/**
* The action to perform upon resume on reboot clear request for a given client.
@@ -129,7 +127,7 @@
@IntDef({ROR_NOT_REQUESTED,
ROR_REQUESTED_NEED_CLEAR,
ROR_REQUESTED_SKIP_CLEAR})
- @interface ResumeOnRebootActionsOnClear{}
+ private @interface ResumeOnRebootActionsOnClear{}
static class Injector {
protected final Context mContext;
@@ -342,9 +340,8 @@
!= PackageManager.PERMISSION_GRANTED
&& mContext.checkCallingOrSelfPermission(android.Manifest.permission.REBOOT)
!= PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Caller or self must have "
- + android.Manifest.permission.RECOVERY + " or "
- + android.Manifest.permission.REBOOT + " for resume on reboot.");
+ throw new SecurityException("Caller must have " + android.Manifest.permission.RECOVERY
+ + " or " + android.Manifest.permission.REBOOT + " for resume on reboot.");
}
}
@@ -414,10 +411,14 @@
Slog.w(TAG, "onPreparedForReboot called when some clients have prepared.");
}
+ if (mCallerPendingRequest.isEmpty()) {
+ Slog.w(TAG, "onPreparedForReboot called but no client has requested.");
+ }
+
// Send intents to notify callers
- for (Map.Entry<String, IntentSender> entry : mCallerPendingRequest.entrySet()) {
- sendPreparedForRebootIntentIfNeeded(entry.getValue());
- mCallerPreparedForReboot.add(entry.getKey());
+ for (int i = 0; i < mCallerPendingRequest.size(); i++) {
+ sendPreparedForRebootIntentIfNeeded(mCallerPendingRequest.valueAt(i));
+ mCallerPreparedForReboot.add(mCallerPendingRequest.keyAt(i));
}
mCallerPendingRequest.clear();
}
@@ -475,9 +476,7 @@
return needClear ? ROR_REQUESTED_NEED_CLEAR : ROR_REQUESTED_SKIP_CLEAR;
}
- @Override // Binder call
- public boolean rebootWithLskf(String packageName, String reason, boolean slotSwitch) {
- enforcePermissionForResumeOnReboot();
+ private boolean rebootWithLskfImpl(String packageName, String reason, boolean slotSwitch) {
if (packageName == null) {
Slog.w(TAG, "Missing packageName when rebooting with lskf.");
return false;
@@ -498,11 +497,29 @@
return true;
}
+ @Override // Binder call for the legacy rebootWithLskf
+ public boolean rebootWithLskfAssumeSlotSwitch(String packageName, String reason) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
+ return rebootWithLskfImpl(packageName, reason, true);
+ }
+
@Override // Binder call
- public synchronized boolean isLskfCaptured(String packageName) {
+ public boolean rebootWithLskf(String packageName, String reason, boolean slotSwitch) {
enforcePermissionForResumeOnReboot();
- if (!mCallerPreparedForReboot.contains(packageName)) {
- Slog.i(TAG, "Reboot requested before prepare completed for caller " + packageName);
+ return rebootWithLskfImpl(packageName, reason, slotSwitch);
+ }
+
+ @Override // Binder call
+ public boolean isLskfCaptured(String packageName) {
+ enforcePermissionForResumeOnReboot();
+ boolean captured;
+ synchronized (this) {
+ captured = mCallerPreparedForReboot.contains(packageName);
+ }
+
+ if (!captured) {
+ Slog.i(TAG, "Reboot requested before prepare completed for caller "
+ + packageName);
return false;
}
return true;
diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java
index 4a32d0f..13cceee 100644
--- a/services/core/java/com/android/server/storage/StorageUserConnection.java
+++ b/services/core/java/com/android/server/storage/StorageUserConnection.java
@@ -135,8 +135,6 @@
*/
public void freeCache(String volumeUuid, long bytes)
throws ExternalStorageServiceException {
- Objects.requireNonNull(volumeUuid);
-
synchronized (mSessionsLock) {
for (String sessionId : mSessions.keySet()) {
mActiveConnection.freeCache(sessionId, volumeUuid, bytes);
diff --git a/services/core/java/com/android/server/utils/Snapshots.java b/services/core/java/com/android/server/utils/Snapshots.java
index 33b2bd4..f2406ab 100644
--- a/services/core/java/com/android/server/utils/Snapshots.java
+++ b/services/core/java/com/android/server/utils/Snapshots.java
@@ -48,7 +48,7 @@
* @param dst The destination array. It must be empty.
* @param src The source array
*/
- public <E> void copy(@NonNull SparseArray<E> dst, @NonNull SparseArray<E> src) {
+ public static <E> void copy(@NonNull SparseArray<E> dst, @NonNull SparseArray<E> src) {
if (dst.size() != 0) {
throw new IllegalArgumentException("copy destination is not empty");
}
@@ -83,7 +83,7 @@
* @param dst The destination array. It must be empty.
* @param src The source array
*/
- public void snapshot(@NonNull SparseIntArray dst, @NonNull SparseIntArray src) {
+ public static void snapshot(@NonNull SparseIntArray dst, @NonNull SparseIntArray src) {
if (dst.size() != 0) {
throw new IllegalArgumentException("snapshot destination is not empty");
}
diff --git a/services/core/java/com/android/server/utils/WatchableIntentResolver.java b/services/core/java/com/android/server/utils/WatchableIntentResolver.java
new file mode 100644
index 0000000..767fc07
--- /dev/null
+++ b/services/core/java/com/android/server/utils/WatchableIntentResolver.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.server.IntentResolver;
+
+import java.util.List;
+
+/**
+ * A watched {@link IntentResolver}. The parameters are inherited from the superclass.
+ * @param <F> The filter type
+ * @param <R> The resolver type.
+ * {@hide}
+ */
+public abstract class WatchableIntentResolver<F, R extends Object>
+ extends IntentResolver<F, R>
+ implements Watchable {
+
+ /**
+ * Watchable machinery
+ */
+ private final Watchable mWatchable = new WatchableImpl();
+ /**
+ * Register an observer to receive change notifications.
+ * @param observer The observer to register.
+ */
+ public void registerObserver(@NonNull Watcher observer) {
+ mWatchable.registerObserver(observer);
+ }
+ /**
+ * Unregister the observer, which will no longer receive change notifications.
+ * @param observer The observer to unregister.
+ */
+ public void unregisterObserver(@NonNull Watcher observer) {
+ mWatchable.unregisterObserver(observer);
+ }
+ /**
+ * Notify listeners that the object has changd. The argument is a hint as to the
+ * source of the change.
+ * @param what The attribute or sub-object that changed, if not null.
+ */
+ public void dispatchChange(@Nullable Watchable what) {
+ mWatchable.dispatchChange(what);
+ }
+ /**
+ * Notify listeners that this object has changed.
+ */
+ protected void onChanged() {
+ dispatchChange(this);
+ }
+
+ @Override
+ public void addFilter(F f) {
+ super.addFilter(f);
+ onChanged();
+ }
+
+ @Override
+ public void removeFilter(F f) {
+ super.removeFilter(f);
+ onChanged();
+ }
+
+ @Override
+ protected void removeFilterInternal(F f) {
+ super.removeFilterInternal(f);
+ onChanged();
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected void sortResults(List<R> results) {
+ super.sortResults(results);
+ onChanged();
+ }
+}
diff --git a/services/core/java/com/android/server/vcn/Android.bp b/services/core/java/com/android/server/vcn/Android.bp
new file mode 100644
index 0000000..5ed204f
--- /dev/null
+++ b/services/core/java/com/android/server/vcn/Android.bp
@@ -0,0 +1,4 @@
+filegroup {
+ name: "framework-vcn-util-sources",
+ srcs: ["util/**/*.java"],
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
new file mode 100644
index 0000000..c060807
--- /dev/null
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
+import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX;
+import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX;
+import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.ParcelUuid;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * TelephonySubscriptionTracker provides a caching layer for tracking active subscription groups.
+ *
+ * <p>This class performs two roles:
+ *
+ * <ol>
+ * <li>De-noises subscription changes by ensuring that only changes in active and ready
+ * subscription groups are acted upon
+ * <li>Caches mapping between subIds and subscription groups
+ * </ol>
+ *
+ * <p>An subscription group is active and ready if any of its contained subIds has had BOTH the
+ * {@link CarrierConfigManager#isConfigForIdentifiedCarrier()} return true, AND the subscription is
+ * listed as active per SubscriptionManager#getAllSubscriptionInfoList().
+ *
+ * <p>Note that due to the asynchronous nature of callbacks and broadcasts, the output of this class
+ * is (only) eventually consistent.
+ *
+ * @hide
+ */
+public class TelephonySubscriptionTracker extends BroadcastReceiver {
+ @NonNull private static final String TAG = TelephonySubscriptionTracker.class.getSimpleName();
+ private static final boolean LOG_DBG = false; // STOPSHIP if true
+
+ @NonNull private final Context mContext;
+ @NonNull private final Handler mHandler;
+ @NonNull private final TelephonySubscriptionTrackerCallback mCallback;
+ @NonNull private final Dependencies mDeps;
+
+ @NonNull private final SubscriptionManager mSubscriptionManager;
+ @NonNull private final CarrierConfigManager mCarrierConfigManager;
+
+ // TODO (Android T+): Add ability to handle multiple subIds per slot.
+ @NonNull private final Map<Integer, Integer> mReadySubIdsBySlotId = new HashMap<>();
+ @NonNull private final OnSubscriptionsChangedListener mSubscriptionChangedListener;
+
+ @NonNull private TelephonySubscriptionSnapshot mCurrentSnapshot;
+
+ public TelephonySubscriptionTracker(
+ @NonNull Context context,
+ @NonNull Handler handler,
+ @NonNull TelephonySubscriptionTrackerCallback callback) {
+ this(context, handler, callback, new Dependencies());
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ TelephonySubscriptionTracker(
+ @NonNull Context context,
+ @NonNull Handler handler,
+ @NonNull TelephonySubscriptionTrackerCallback callback,
+ @NonNull Dependencies deps) {
+ mContext = Objects.requireNonNull(context, "Missing context");
+ mHandler = Objects.requireNonNull(handler, "Missing handler");
+ mCallback = Objects.requireNonNull(callback, "Missing callback");
+ mDeps = Objects.requireNonNull(deps, "Missing deps");
+
+ mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
+ mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
+
+ mSubscriptionChangedListener =
+ new OnSubscriptionsChangedListener() {
+ @Override
+ public void onSubscriptionsChanged() {
+ handleSubscriptionsChanged();
+ }
+ };
+ }
+
+ /** Registers the receivers, and starts tracking subscriptions. */
+ public void register() {
+ mContext.registerReceiver(
+ this, new IntentFilter(ACTION_CARRIER_CONFIG_CHANGED), null, mHandler);
+ mSubscriptionManager.addOnSubscriptionsChangedListener(
+ new HandlerExecutor(mHandler), mSubscriptionChangedListener);
+ }
+
+ /** Unregisters the receivers, and stops tracking subscriptions. */
+ public void unregister() {
+ mContext.unregisterReceiver(this);
+ mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionChangedListener);
+ }
+
+ /**
+ * Handles subscription changes, correlating available subscriptions and loaded carrier configs
+ *
+ * <p>The subscription change listener is registered with a HandlerExecutor backed by mHandler,
+ * so callbacks & broadcasts are all serialized on mHandler, avoiding the need for locking.
+ */
+ public void handleSubscriptionsChanged() {
+ final Set<ParcelUuid> activeSubGroups = new ArraySet<>();
+ final Map<Integer, ParcelUuid> newSubIdToGroupMap = new HashMap<>();
+
+ final List<SubscriptionInfo> allSubs = mSubscriptionManager.getAllSubscriptionInfoList();
+ if (allSubs == null) {
+ return; // Telephony crashed; no way to verify subscriptions.
+ }
+
+ // If allSubs is empty, no subscriptions exist. Cache will be cleared by virtue of no active
+ // subscriptions
+ for (SubscriptionInfo subInfo : allSubs) {
+ if (subInfo.getGroupUuid() == null) {
+ continue;
+ }
+
+ // Build subId -> subGrp cache
+ newSubIdToGroupMap.put(subInfo.getSubscriptionId(), subInfo.getGroupUuid());
+
+ // Update subscription groups that are both ready, and active. For a group to be
+ // considered active, both of the following must be true:
+ //
+ // 1. A final CARRIER_CONFIG_CHANGED (where config is for an identified carrier)
+ // broadcast must have been received for the subId
+ // 2. A active subscription (is loaded into a SIM slot) must be part of the subscription
+ // group.
+ if (subInfo.getSimSlotIndex() != INVALID_SIM_SLOT_INDEX
+ && mReadySubIdsBySlotId.values().contains(subInfo.getSubscriptionId())) {
+ activeSubGroups.add(subInfo.getGroupUuid());
+ }
+ }
+
+ final TelephonySubscriptionSnapshot newSnapshot =
+ new TelephonySubscriptionSnapshot(newSubIdToGroupMap, activeSubGroups);
+
+ // If snapshot was meaningfully updated, fire the callback
+ if (!newSnapshot.equals(mCurrentSnapshot)) {
+ mCurrentSnapshot = newSnapshot;
+ mHandler.post(
+ () -> {
+ mCallback.onNewSnapshot(newSnapshot);
+ });
+ }
+ }
+
+ /**
+ * Broadcast receiver for ACTION_CARRIER_CONFIG_CHANGED
+ *
+ * <p>The broadcast receiver is registered with mHandler, so callbacks & broadcasts are all
+ * serialized on mHandler, avoiding the need for locking.
+ */
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // Accept sticky broadcasts; if CARRIER_CONFIG_CHANGED was previously broadcast and it
+ // already was for an identified carrier, we can stop waiting for initial load to complete
+ if (!ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) {
+ return;
+ }
+
+ final int subId = intent.getIntExtra(EXTRA_SUBSCRIPTION_INDEX, INVALID_SUBSCRIPTION_ID);
+ final int slotId = intent.getIntExtra(EXTRA_SLOT_INDEX, INVALID_SIM_SLOT_INDEX);
+
+ if (slotId == INVALID_SIM_SLOT_INDEX) {
+ return;
+ }
+
+ if (SubscriptionManager.isValidSubscriptionId(subId)) {
+ final PersistableBundle carrierConfigs = mCarrierConfigManager.getConfigForSubId(subId);
+ if (mDeps.isConfigForIdentifiedCarrier(carrierConfigs)) {
+ Slog.v(TAG, String.format("SubId %s ready for SlotId %s", subId, slotId));
+ mReadySubIdsBySlotId.put(slotId, subId);
+ handleSubscriptionsChanged();
+ }
+ } else {
+ Slog.v(TAG, "Slot unloaded: " + slotId);
+ mReadySubIdsBySlotId.remove(slotId);
+ handleSubscriptionsChanged();
+ }
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ void setReadySubIdsBySlotId(Map<Integer, Integer> readySubIdsBySlotId) {
+ mReadySubIdsBySlotId.putAll(readySubIdsBySlotId);
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ Map<Integer, Integer> getReadySubIdsBySlotId() {
+ return Collections.unmodifiableMap(mReadySubIdsBySlotId);
+ }
+
+ /** TelephonySubscriptionSnapshot is a class containing info about active subscriptions */
+ public static class TelephonySubscriptionSnapshot {
+ private final Map<Integer, ParcelUuid> mSubIdToGroupMap;
+ private final Set<ParcelUuid> mActiveGroups;
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ TelephonySubscriptionSnapshot(
+ @NonNull Map<Integer, ParcelUuid> subIdToGroupMap,
+ @NonNull Set<ParcelUuid> activeGroups) {
+ mSubIdToGroupMap = Collections.unmodifiableMap(
+ Objects.requireNonNull(subIdToGroupMap, "subIdToGroupMap was null"));
+ mActiveGroups = Collections.unmodifiableSet(
+ Objects.requireNonNull(activeGroups, "activeGroups was null"));
+ }
+
+ /** Returns the active subscription groups */
+ @NonNull
+ public Set<ParcelUuid> getActiveSubscriptionGroups() {
+ return mActiveGroups;
+ }
+
+ /** Returns the Subscription Group for a given subId. */
+ @Nullable
+ public ParcelUuid getGroupForSubId(int subId) {
+ return mSubIdToGroupMap.get(subId);
+ }
+
+ /**
+ * Returns all the subIds in a given group, including available, but inactive subscriptions.
+ */
+ @NonNull
+ public Set<Integer> getAllSubIdsInGroup(ParcelUuid subGrp) {
+ final Set<Integer> subIds = new ArraySet<>();
+
+ for (Entry<Integer, ParcelUuid> entry : mSubIdToGroupMap.entrySet()) {
+ if (subGrp.equals(entry.getValue())) {
+ subIds.add(entry.getKey());
+ }
+ }
+
+ return subIds;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mSubIdToGroupMap, mActiveGroups);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof TelephonySubscriptionSnapshot)) {
+ return false;
+ }
+
+ final TelephonySubscriptionSnapshot other = (TelephonySubscriptionSnapshot) obj;
+
+ return mSubIdToGroupMap.equals(other.mSubIdToGroupMap)
+ && mActiveGroups.equals(other.mActiveGroups);
+ }
+ }
+
+ /**
+ * Interface for listening to changes in subscriptions
+ *
+ * @see TelephonySubscriptionTracker
+ */
+ public interface TelephonySubscriptionTrackerCallback {
+ /**
+ * Called when subscription information changes, and a new subscription snapshot was taken
+ *
+ * @param snapshot the snapshot of subscription information.
+ */
+ void onNewSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot);
+ }
+
+ /** External static dependencies for test injection */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static class Dependencies {
+ /** Checks if the given bundle is for an identified carrier */
+ public boolean isConfigForIdentifiedCarrier(PersistableBundle bundle) {
+ return CarrierConfigManager.isConfigForIdentifiedCarrier(bundle);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 9efa249..3390d67 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1759,6 +1759,9 @@
final TaskSnapshot snapshot =
mWmService.mTaskSnapshotController.getSnapshot(task.mTaskId, task.mUserId,
false /* restoreFromDisk */, false /* isLowResolution */);
+ final int typeParameter = mWmService.mStartingSurfaceController
+ .makeStartingWindowTypeParameter(newTask, taskSwitch, processRunning,
+ allowTaskSnapshot, activityCreated);
final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
allowTaskSnapshot, activityCreated, snapshot);
@@ -1773,7 +1776,7 @@
return false;
}
}
- return createSnapshot(snapshot);
+ return createSnapshot(snapshot, typeParameter);
}
// If this is a translucent window, then don't show a starting window -- the current
@@ -1833,18 +1836,18 @@
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SplashScreenStartingData");
mStartingData = new SplashScreenStartingData(mWmService, pkg,
theme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
- getMergedOverrideConfiguration());
+ getMergedOverrideConfiguration(), typeParameter);
scheduleAddStartingWindow();
return true;
}
- private boolean createSnapshot(TaskSnapshot snapshot) {
+ private boolean createSnapshot(TaskSnapshot snapshot, int typeParams) {
if (snapshot == null) {
return false;
}
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SnapshotStartingData");
- mStartingData = new SnapshotStartingData(mWmService, snapshot);
+ mStartingData = new SnapshotStartingData(mWmService, snapshot, typeParams);
scheduleAddStartingWindow();
return true;
}
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index 07729d1..029056a 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -204,7 +204,7 @@
}
private void dim(SurfaceControl.Transaction t, WindowContainer container, int relativeLayer,
- float alpha) {
+ float alpha, int blurRadius) {
final DimState d = getDimState(container);
if (d == null) {
@@ -220,6 +220,7 @@
t.setLayer(d.mDimLayer, Integer.MAX_VALUE);
}
t.setAlpha(d.mDimLayer, alpha);
+ t.setBackgroundBlurRadius(d.mDimLayer, blurRadius);
d.mDimming = true;
}
@@ -247,7 +248,7 @@
* @param alpha The alpha at which to Dim.
*/
void dimAbove(SurfaceControl.Transaction t, float alpha) {
- dim(t, null, 1, alpha);
+ dim(t, null, 1, alpha, 0);
}
/**
@@ -260,19 +261,21 @@
* @param alpha The alpha at which to Dim.
*/
void dimAbove(SurfaceControl.Transaction t, WindowContainer container, float alpha) {
- dim(t, container, 1, alpha);
+ dim(t, container, 1, alpha, 0);
}
/**
* Like {@link #dimAbove} but places the dim below the given container.
*
- * @param t A transaction in which to apply the Dim.
- * @param container The container which to dim below. Should be a child of our host.
- * @param alpha The alpha at which to Dim.
+ * @param t A transaction in which to apply the Dim.
+ * @param container The container which to dim below. Should be a child of our host.
+ * @param alpha The alpha at which to Dim.
+ * @param blurRadius The amount of blur added to the Dim.
*/
- void dimBelow(SurfaceControl.Transaction t, WindowContainer container, float alpha) {
- dim(t, container, -1, alpha);
+ void dimBelow(SurfaceControl.Transaction t, WindowContainer container, float alpha,
+ int blurRadius) {
+ dim(t, container, -1, alpha, blurRadius);
}
/**
diff --git a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
index c475da3..53f7009 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
@@ -134,7 +134,7 @@
@Override
public DisplayAreaAppearedInfo createTaskDisplayArea(IDisplayAreaOrganizer organizer,
- int displayId, int rootFeatureId, String name) {
+ int displayId, int parentFeatureId, String name) {
enforceTaskPermission("createTaskDisplayArea()");
final long uid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
@@ -149,13 +149,26 @@
+ displayId);
}
- final DisplayArea root = display.getItemFromDisplayAreas(da ->
- da.asRootDisplayArea() != null && da.mFeatureId == rootFeatureId
- ? da
+ // The parentFeatureId can be either a RootDisplayArea or a TaskDisplayArea.
+ // Check if there is a RootDisplayArea with the given parentFeatureId.
+ final RootDisplayArea parentRoot = display.getItemFromDisplayAreas(da ->
+ da.asRootDisplayArea() != null && da.mFeatureId == parentFeatureId
+ ? da.asRootDisplayArea()
: null);
- if (root == null) {
- throw new IllegalArgumentException("Can't find RootDisplayArea with featureId="
- + rootFeatureId);
+ final TaskDisplayArea parentTda;
+ if (parentRoot == null) {
+ // There is no RootDisplayArea matching the parentFeatureId.
+ // Check if there is a TaskDisplayArea with the given parentFeatureId.
+ parentTda = display.getItemFromTaskDisplayAreas(taskDisplayArea ->
+ taskDisplayArea.mFeatureId == parentFeatureId
+ ? taskDisplayArea
+ : null);
+ } else {
+ parentTda = null;
+ }
+ if (parentRoot == null && parentTda == null) {
+ throw new IllegalArgumentException(
+ "Can't find a parent DisplayArea with featureId=" + parentFeatureId);
}
final int taskDisplayAreaFeatureId = mNextTaskDisplayAreaFeatureId++;
@@ -166,10 +179,13 @@
// Oh well...
}
- final TaskDisplayArea tda = createTaskDisplayArea(root.asRootDisplayArea(), name,
- taskDisplayAreaFeatureId);
- return organizeDisplayArea(organizer, tda,
+ final TaskDisplayArea tda = parentRoot != null
+ ? createTaskDisplayArea(parentRoot, name, taskDisplayAreaFeatureId)
+ : createTaskDisplayArea(parentTda, name, taskDisplayAreaFeatureId);
+ final DisplayAreaAppearedInfo tdaInfo = organizeDisplayArea(organizer, tda,
"DisplayAreaOrganizerController.createTaskDisplayArea");
+ mOrganizersByFeatureIds.put(taskDisplayAreaFeatureId, organizer);
+ return tdaInfo;
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -196,6 +212,7 @@
+ "TaskDisplayArea=" + taskDisplayArea);
}
+ mOrganizersByFeatureIds.remove(taskDisplayArea.mFeatureId);
deleteTaskDisplayArea(taskDisplayArea);
}
} finally {
@@ -253,6 +270,9 @@
new SurfaceControl(displayArea.getSurfaceControl(), callsite));
}
+ /**
+ * Creates a {@link TaskDisplayArea} as the topmost TDA below the given {@link RootDisplayArea}.
+ */
private TaskDisplayArea createTaskDisplayArea(RootDisplayArea root, String name,
int taskDisplayAreaFeatureId) {
final TaskDisplayArea taskDisplayArea = new TaskDisplayArea(root.mDisplayContent,
@@ -283,6 +303,21 @@
return taskDisplayArea;
}
+ /**
+ * Creates a {@link TaskDisplayArea} as the topmost child of the given {@link TaskDisplayArea}.
+ */
+ private TaskDisplayArea createTaskDisplayArea(TaskDisplayArea parentTda, String name,
+ int taskDisplayAreaFeatureId) {
+ final TaskDisplayArea taskDisplayArea = new TaskDisplayArea(parentTda.mDisplayContent,
+ parentTda.mWmService, name, taskDisplayAreaFeatureId,
+ true /* createdByOrganizer */);
+
+ // Insert the TaskDisplayArea on the top.
+ parentTda.addChild(taskDisplayArea, WindowContainer.POSITION_TOP);
+
+ return taskDisplayArea;
+ }
+
private void deleteTaskDisplayArea(TaskDisplayArea taskDisplayArea) {
taskDisplayArea.setOrganizer(null);
mService.mRootWindowContainer.mTaskSupervisor.beginDeferResume();
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
index f8c3754..d4b319a 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
@@ -99,41 +99,23 @@
// Define the features that will be supported under the root of the whole logical
// display. The policy will build the DisplayArea hierarchy based on this.
- final HierarchyBuilder rootHierarchy = new HierarchyBuilder(root);
- if (content.isTrusted()) {
- // Only trusted display can have system decorations.
- configureTrustedHierarchyBuilder(rootHierarchy, wmService, content);
- }
- // Set the essential containers (even the display doesn't support IME).
- rootHierarchy.setImeContainer(imeContainer).setTaskDisplayAreas(tdaList);
-
- // Instantiate the policy with the hierarchy defined above. This will create and attach
- // all the necessary DisplayAreas to the root.
- return new DisplayAreaPolicyBuilder().setRootHierarchy(rootHierarchy).build(wmService);
- }
-
- private void configureTrustedHierarchyBuilder(HierarchyBuilder rootHierarchy,
- WindowManagerService wmService, DisplayContent content) {
- // WindowedMagnification should be on the top so that there is only one surface
- // to be magnified.
- rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "WindowedMagnification",
- FEATURE_WINDOWED_MAGNIFICATION)
- .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
- .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
- // Make the DA dimmable so that the magnify window also mirrors the dim layer.
- .setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
- .build());
- if (content.isDefaultDisplay) {
- // Only default display can have cutout.
- // See LocalDisplayAdapter.LocalDisplayDevice#getDisplayDeviceInfoLocked.
- rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "HideDisplayCutout",
- FEATURE_HIDE_DISPLAY_CUTOUT)
- .all()
- .except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL,
- TYPE_STATUS_BAR, TYPE_NOTIFICATION_SHADE)
- .build());
- }
- rootHierarchy
+ HierarchyBuilder rootHierarchy = new HierarchyBuilder(root)
+ // WindowedMagnification should be on the top so that there is only one surface
+ // to be magnified.
+ .addFeature(new Feature.Builder(wmService.mPolicy, "WindowedMagnification",
+ FEATURE_WINDOWED_MAGNIFICATION)
+ .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
+ .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
+ // Make the DA dimmable so that the magnify window also mirrors the dim
+ // layer
+ .setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
+ .build())
+ .addFeature(new Feature.Builder(wmService.mPolicy, "HideDisplayCutout",
+ FEATURE_HIDE_DISPLAY_CUTOUT)
+ .all()
+ .except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL, TYPE_STATUS_BAR,
+ TYPE_NOTIFICATION_SHADE)
+ .build())
.addFeature(new Feature.Builder(wmService.mPolicy, "OneHanded",
FEATURE_ONE_HANDED)
.all()
@@ -149,7 +131,13 @@
.addFeature(new Feature.Builder(wmService.mPolicy, "ImePlaceholder",
FEATURE_IME_PLACEHOLDER)
.and(TYPE_INPUT_METHOD, TYPE_INPUT_METHOD_DIALOG)
- .build());
+ .build())
+ .setImeContainer(imeContainer)
+ .setTaskDisplayAreas(tdaList);
+
+ // Instantiate the policy with the hierarchy defined above. This will create and attach
+ // all the necessary DisplayAreas to the root.
+ return new DisplayAreaPolicyBuilder().setRootHierarchy(rootHierarchy).build(wmService);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index fc9753c..4c60a3d 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -283,6 +283,12 @@
*/
private SurfaceControl mOverlayLayer;
+ /**
+ * The direct child layer of the display to put all non-overlay windows. This is also used for
+ * screen rotation animation so that there is a parent layer to put the animation leash.
+ */
+ private final SurfaceControl mWindowingLayer;
+
// Contains all IME window containers. Note that the z-ordering of the IME windows will depend
// on the IME target. We mainly have this container grouping so we can keep track of all the IME
// window containers together and move them in-sync if/when needed. We use a subclass of
@@ -294,7 +300,6 @@
final DisplayAreaPolicy mDisplayAreaPolicy;
private WindowState mTmpWindow;
- private WindowState mTmpWindow2;
private boolean mUpdateImeTarget;
private boolean mTmpInitial;
private int mMaxUiWidth;
@@ -459,10 +464,6 @@
private final ApplySurfaceChangesTransactionState mTmpApplySurfaceChangesTransactionState =
new ApplySurfaceChangesTransactionState();
- // True if this display is in the process of being removed. Used to determine if the removal of
- // the display's direct children should be allowed.
- private boolean mRemovingDisplay = false;
-
// {@code false} if this display is in the processing of being created.
private boolean mDisplayReady = false;
@@ -1023,6 +1024,27 @@
.setContainerLayer()
.setCallsite("DisplayContent");
mSurfaceControl = b.setName("Root").setContainerLayer().build();
+
+ // Setup the policy and build the display area hierarchy.
+ mDisplayAreaPolicy = mWmService.getDisplayAreaPolicyProvider().instantiate(
+ mWmService, this /* content */, this /* root */, mImeWindowsContainers);
+
+ final List<DisplayArea<? extends WindowContainer>> areas =
+ mDisplayAreaPolicy.getDisplayAreas(FEATURE_WINDOWED_MAGNIFICATION);
+ final DisplayArea<?> area = areas.size() == 1 ? areas.get(0) : null;
+ if (area != null && area.getParent() == this) {
+ // The windowed magnification area should contain all non-overlay windows, so just use
+ // it as the windowing layer.
+ mWindowingLayer = area.mSurfaceControl;
+ } else {
+ // Need an additional layer for screen level animation, so move the layer containing
+ // the windows to the new root.
+ mWindowingLayer = mSurfaceControl;
+ mSurfaceControl = b.setName("RootWrapper").build();
+ getPendingTransaction().reparent(mWindowingLayer, mSurfaceControl)
+ .show(mWindowingLayer);
+ }
+
mOverlayLayer = b.setName("Display Overlays").setParent(mSurfaceControl).build();
getPendingTransaction()
@@ -1033,10 +1055,6 @@
.show(mOverlayLayer);
getPendingTransaction().apply();
- // Setup the policy and build the display area hierarchy.
- mDisplayAreaPolicy = mWmService.getDisplayAreaPolicyProvider().instantiate(
- mWmService, this /* content */, this /* root */, mImeWindowsContainers);
-
// Sets the display content for the children.
onDisplayChanged(this);
@@ -2300,10 +2318,9 @@
return count[0];
}
- @VisibleForTesting
@Nullable
Task getTopRootTask() {
- return getItemFromTaskDisplayAreas(TaskDisplayArea::getTopRootTask);
+ return getRootTask(t -> true);
}
/**
@@ -2797,7 +2814,6 @@
@Override
void removeImmediately() {
- mRemovingDisplay = true;
mDeferredRemoval = false;
try {
if (mParentWindow != null) {
@@ -2821,7 +2837,6 @@
mWmService.mDisplayNotificationController.dispatchDisplayRemoved(this);
} finally {
mDisplayReady = false;
- mRemovingDisplay = false;
}
// Apply the pending transaction here since we may not be able to reach the DisplayContent
@@ -4191,7 +4206,6 @@
// Used to indicate that we have processed the dream window and all additional attached
// windows are behind it.
- mTmpWindow2 = mTmpWindow;
mTmpWindow = null;
// Now perform layout of attached windows, which usually depend on the position of the
@@ -4861,19 +4875,8 @@
}, false /* traverseTopToBottom */);
}
- private DisplayArea getWindowContainers() {
- List<DisplayArea<? extends WindowContainer>> windowContainers =
- mDisplayAreaPolicy.getDisplayAreas(FEATURE_WINDOWED_MAGNIFICATION);
- if (windowContainers.size() != 1) {
- throw new IllegalStateException("There should be only one DisplayArea for "
- + "FEATURE_WINDOWED_MAGNIFICATION");
- }
- return windowContainers.get(0);
- }
-
- @VisibleForTesting
SurfaceControl getWindowingLayer() {
- return getWindowContainers().getSurfaceControl();
+ return mWindowingLayer;
}
DisplayArea.Tokens getImeContainer() {
@@ -5479,12 +5482,12 @@
return;
}
- // Check if all task display areas have only the empty home stacks left.
- boolean hasNonEmptyHomeStack = forAllRootTasks(stack ->
- !stack.isActivityTypeHome() || stack.hasChild());
- if (!hasNonEmptyHomeStack && getRootTaskCount() > 0) {
- // Release this display if only empty home stack(s) are left. This display will be
- // released along with the stack(s) removal.
+ // Check if all task display areas have only the empty home root tasks left.
+ boolean hasNonEmptyHomeRootTask = forAllRootTasks(rootTask ->
+ !rootTask.isActivityTypeHome() || rootTask.hasChild());
+ if (!hasNonEmptyHomeRootTask && getRootTaskCount() > 0) {
+ // Release this display if only empty home root task(s) are left. This display will be
+ // released along with the root task(s) removal.
forAllRootTasks(Task::removeIfPossible);
} else if (getTopRootTask() == null) {
removeIfPossible();
@@ -5525,12 +5528,14 @@
return;
}
mInEnsureActivitiesVisible = true;
+ mAtmService.mTaskSupervisor.beginActivityVisibilityUpdate();
try {
- forAllTaskDisplayAreas(taskDisplayArea -> {
- taskDisplayArea.ensureActivitiesVisible(starting, configChanges,
- preserveWindows, notifyClients, userLeaving);
+ forAllRootTasks(rootTask -> {
+ rootTask.ensureActivitiesVisible(starting, configChanges, preserveWindows,
+ notifyClients, userLeaving);
});
} finally {
+ mAtmService.mTaskSupervisor.endActivityVisibilityUpdate();
mInEnsureActivitiesVisible = false;
}
}
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index 35f5615..6e89581 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -26,9 +26,7 @@
import android.annotation.NonNull;
import android.os.Debug;
import android.os.IBinder;
-import android.os.RemoteException;
import android.util.Slog;
-import android.view.IWindow;
import android.view.InputApplicationHandle;
import android.view.KeyEvent;
import android.view.WindowManager;
@@ -37,7 +35,6 @@
import com.android.server.input.InputManagerService;
import java.io.PrintWriter;
-import java.util.concurrent.atomic.AtomicReference;
final class InputManagerCallback implements InputManagerService.WindowManagerCallbacks {
private static final String TAG = TAG_WITH_CLASS_NAME ? "InputManagerCallback" : TAG_WM;
@@ -60,13 +57,6 @@
// which point the ActivityManager will enable dispatching.
private boolean mInputDispatchEnabled;
- // TODO(b/141749603)) investigate if this can be part of client focus change dispatch
- // Tracks the currently focused window used to update pointer capture state in clients
- private AtomicReference<IWindow> mFocusedWindow = new AtomicReference<>();
-
- // Tracks focused window pointer capture state
- private boolean mFocusedWindowHasCapture;
-
public InputManagerCallback(WindowManagerService service) {
mService = service;
}
@@ -234,59 +224,9 @@
}
@Override
- public boolean notifyFocusChanged(IBinder oldToken, IBinder newToken) {
- boolean requestRefreshConfiguration = false;
- final IWindow newFocusedWindow;
- final WindowState win;
-
- // TODO(b/141749603) investigate if this can be part of client focus change dispatch
- synchronized (mService.mGlobalLock) {
- win = mService.mInputToWindowMap.get(newToken);
- }
- newFocusedWindow = (win != null) ? win.mClient : null;
-
- final IWindow focusedWindow = mFocusedWindow.get();
- if (focusedWindow != null) {
- if (newFocusedWindow != null
- && newFocusedWindow.asBinder() == focusedWindow.asBinder()) {
- Slog.w(TAG, "notifyFocusChanged called with unchanged mFocusedWindow="
- + focusedWindow);
- return false;
- }
- requestRefreshConfiguration = dispatchPointerCaptureChanged(focusedWindow, false);
- }
- mFocusedWindow.set(newFocusedWindow);
- mService.mH.sendMessage(PooledLambda.obtainMessage(mService::reportFocusChanged,
- oldToken, newToken));
- return requestRefreshConfiguration;
- }
-
- @Override
- public boolean requestPointerCapture(IBinder windowToken, boolean enabled) {
- final IWindow focusedWindow = mFocusedWindow.get();
- if (focusedWindow == null || focusedWindow.asBinder() != windowToken) {
- Slog.e(TAG, "requestPointerCapture called for a window that has no focus: "
- + windowToken);
- return false;
- }
- if (mFocusedWindowHasCapture == enabled) {
- Slog.i(TAG, "requestPointerCapture: already " + (enabled ? "enabled" : "disabled"));
- return false;
- }
- return dispatchPointerCaptureChanged(focusedWindow, enabled);
- }
-
- private boolean dispatchPointerCaptureChanged(IWindow focusedWindow, boolean enabled) {
- if (mFocusedWindowHasCapture != enabled) {
- mFocusedWindowHasCapture = enabled;
- try {
- focusedWindow.dispatchPointerCaptureChanged(enabled);
- } catch (RemoteException ex) {
- /* ignore */
- }
- return true;
- }
- return false;
+ public void notifyFocusChanged(IBinder oldToken, IBinder newToken) {
+ mService.mH.sendMessage(PooledLambda.obtainMessage(
+ mService::reportFocusChanged, oldToken, newToken));
}
/** Waits until the built-in input devices have been configured. */
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 05dcd36..5bcb287 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -413,9 +413,10 @@
@Override
public void onRootTaskOrderChanged(Task rootTask) {
- ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "onStackOrderChanged(): stack=%s", rootTask);
- if (mDefaultTaskDisplayArea.getIndexOf(rootTask) == -1 || !rootTask.shouldBeVisible(null)) {
- // The stack is not visible, so ignore this change
+ ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "onRootTaskOrderChanged(): rootTask=%s", rootTask);
+ if (mDefaultTaskDisplayArea.getRootTask(t -> t == rootTask) == null
+ || !rootTask.shouldBeVisible(null)) {
+ // The root task is not visible, so ignore this change
return;
}
final RecentsAnimationController controller =
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 8ca49eb..d926a36 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1013,7 +1013,7 @@
mWmService.scheduleAnimationLocked();
// Send any pending task-info changes that were queued-up during a layout deferment
- mWmService.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
+ mWmService.mAtmService.mTaskOrganizerController.dispatchPendingTaskInfoChanges();
if (DEBUG_WINDOW_TRACE) Slog.e(TAG, "performSurfacePlacementInner exit");
}
@@ -1828,19 +1828,19 @@
}
/**
- * @return a list of activities which are the top ones in each visible stack. The first
+ * @return a list of activities which are the top ones in each visible root task. The first
* entry will be the focused activity.
*/
List<IBinder> getTopVisibleActivities() {
final ArrayList<IBinder> topActivityTokens = new ArrayList<>();
- final Task topFocusedStack = getTopDisplayFocusedRootTask();
+ final Task topFocusedRootTask = getTopDisplayFocusedRootTask();
// Traverse all displays.
- forAllRootTasks(stack -> {
- // Get top activity from a visible stack and add it to the list.
- if (stack.shouldBeVisible(null /* starting */)) {
- final ActivityRecord top = stack.getTopNonFinishingActivity();
+ forAllRootTasks(rootTask -> {
+ // Get top activity from a visible root task and add it to the list.
+ if (rootTask.shouldBeVisible(null /* starting */)) {
+ final ActivityRecord top = rootTask.getTopNonFinishingActivity();
if (top != null) {
- if (stack == topFocusedStack) {
+ if (rootTask == topFocusedRootTask) {
topActivityTokens.add(0, top.appToken);
} else {
topActivityTokens.add(top.appToken);
@@ -1854,9 +1854,9 @@
@Nullable
Task getTopDisplayFocusedRootTask() {
for (int i = getChildCount() - 1; i >= 0; --i) {
- final Task focusedStack = getChildAt(i).getFocusedRootTask();
- if (focusedStack != null) {
- return focusedStack;
+ final Task focusedRootTask = getChildAt(i).getFocusedRootTask();
+ if (focusedRootTask != null) {
+ return focusedRootTask;
}
}
return null;
@@ -1864,15 +1864,15 @@
@Nullable
ActivityRecord getTopResumedActivity() {
- final Task focusedStack = getTopDisplayFocusedRootTask();
- if (focusedStack == null) {
+ final Task focusedRootTask = getTopDisplayFocusedRootTask();
+ if (focusedRootTask == null) {
return null;
}
- final ActivityRecord resumedActivity = focusedStack.getResumedActivity();
+ final ActivityRecord resumedActivity = focusedRootTask.getResumedActivity();
if (resumedActivity != null && resumedActivity.app != null) {
return resumedActivity;
}
- // The top focused stack might not have a resumed activity yet - look on all displays in
+ // The top focused root task might not have a resumed activity yet - look on all displays in
// focus order.
return getItemFromTaskDisplayAreas(TaskDisplayArea::getFocusedActivity);
}
@@ -1997,36 +1997,36 @@
}
boolean switchUser(int userId, UserState uss) {
- final Task topFocusedStack = getTopDisplayFocusedRootTask();
- final int focusStackId = topFocusedStack != null
- ? topFocusedStack.getRootTaskId() : INVALID_TASK_ID;
- // We dismiss the docked stack whenever we switch users.
+ final Task topFocusedRootTask = getTopDisplayFocusedRootTask();
+ final int focusRootTaskId = topFocusedRootTask != null
+ ? topFocusedRootTask.getRootTaskId() : INVALID_TASK_ID;
+ // We dismiss the docked root task whenever we switch users.
if (getDefaultTaskDisplayArea().isSplitScreenModeActivated()) {
getDefaultTaskDisplayArea().onSplitScreenModeDismissed();
}
- // Also dismiss the pinned stack whenever we switch users. Removing the pinned stack will
- // also cause all tasks to be moved to the fullscreen stack at a position that is
+ // Also dismiss the pinned root task whenever we switch users. Removing the pinned root task
+ // will also cause all tasks to be moved to the fullscreen root task at a position that is
// appropriate.
removeRootTasksInWindowingModes(WINDOWING_MODE_PINNED);
- mUserRootTaskInFront.put(mCurrentUser, focusStackId);
+ mUserRootTaskInFront.put(mCurrentUser, focusRootTaskId);
mCurrentUser = userId;
mTaskSupervisor.mStartingUsers.add(uss);
- forAllRootTasks(stack -> {
- stack.switchUser(userId);
+ forAllRootTasks(rootTask -> {
+ rootTask.switchUser(userId);
});
- final int restoreStackId = mUserRootTaskInFront.get(userId);
- Task stack = getRootTask(restoreStackId);
- if (stack == null) {
- stack = getDefaultTaskDisplayArea().getOrCreateRootHomeTask();
+ final int restoreRootTaskId = mUserRootTaskInFront.get(userId);
+ Task rootTask = getRootTask(restoreRootTaskId);
+ if (rootTask == null) {
+ rootTask = getDefaultTaskDisplayArea().getOrCreateRootHomeTask();
}
- final boolean homeInFront = stack.isActivityTypeHome();
- if (stack.isOnHomeDisplay()) {
- stack.moveToFront("switchUserOnHomeDisplay");
+ final boolean homeInFront = rootTask.isActivityTypeHome();
+ if (rootTask.isOnHomeDisplay()) {
+ rootTask.moveToFront("switchUserOnHomeDisplay");
} else {
- // Stack was moved to another display while user was swapped out.
+ // Root task was moved to another display while user was swapped out.
resumeHomeActivity(null, "switchUserOnOtherDisplay", getDefaultTaskDisplayArea());
}
return homeInFront;
@@ -2350,7 +2350,7 @@
return result;
}
- void applySleepTokens(boolean applyToStacks) {
+ void applySleepTokens(boolean applyToRootTasks) {
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
// Set the sleeping state of the display.
final DisplayContent display = getChildAt(displayNdx);
@@ -2360,17 +2360,17 @@
}
display.setIsSleeping(displayShouldSleep);
- if (!applyToStacks) {
+ if (!applyToRootTasks) {
continue;
}
- // Set the sleeping state of the stacks on the display.
- display.forAllRootTasks(stack -> {
+ // Set the sleeping state of the root tasks on the display.
+ display.forAllRootTasks(rootTask -> {
if (displayShouldSleep) {
- stack.goToSleepIfPossible(false /* shuttingDown */);
+ rootTask.goToSleepIfPossible(false /* shuttingDown */);
} else {
- stack.awakeFromSleepingLocked();
- if (stack.isFocusedStackOnDisplay()
+ rootTask.awakeFromSleepingLocked();
+ if (rootTask.isFocusedStackOnDisplay()
&& !mTaskSupervisor.getKeyguardController()
.isKeyguardOrAodShowing(display.mDisplayId)) {
// If the keyguard is unlocked - resume immediately.
@@ -2378,13 +2378,13 @@
// process the keyguard going away, which can happen before the sleep
// token is released. As a result, it is important we resume the
// activity here.
- stack.resumeTopActivityUncheckedLocked(null, null);
+ rootTask.resumeTopActivityUncheckedLocked(null, null);
}
// The visibility update must not be called before resuming the top, so the
// display orientation can be updated first if needed. Otherwise there may
// have redundant configuration changes due to apply outdated display
// orientation (from keyguard) to activity.
- stack.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
+ rootTask.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
false /* preserveWindows */);
}
});
@@ -2427,7 +2427,7 @@
task.fillTaskInfo(info);
// A task might be not attached to a display.
- info.position = taskDisplayArea != null ? taskDisplayArea.getIndexOf(task) : 0;
+ info.position = taskDisplayArea != null ? taskDisplayArea.getTaskIndexOf(task) : 0;
info.visible = task.shouldBeVisible(null);
task.getBounds(info.bounds);
@@ -2471,21 +2471,21 @@
}
RootTaskInfo getRootTaskInfo(int windowingMode, int activityType) {
- final Task stack = getRootTask(windowingMode, activityType);
- return (stack != null) ? getRootTaskInfo(stack) : null;
+ final Task rootTask = getRootTask(windowingMode, activityType);
+ return (rootTask != null) ? getRootTaskInfo(rootTask) : null;
}
RootTaskInfo getRootTaskInfo(int windowingMode, int activityType, int displayId) {
- final Task stack = getRootTask(windowingMode, activityType, displayId);
- return (stack != null) ? getRootTaskInfo(stack) : null;
+ final Task rootTask = getRootTask(windowingMode, activityType, displayId);
+ return (rootTask != null) ? getRootTaskInfo(rootTask) : null;
}
/** If displayId == INVALID_DISPLAY, this will get root task infos on all displays */
ArrayList<RootTaskInfo> getAllRootTaskInfos(int displayId) {
final ArrayList<RootTaskInfo> list = new ArrayList<>();
if (displayId == INVALID_DISPLAY) {
- forAllRootTasks(stack -> {
- list.add(getRootTaskInfo(stack));
+ forAllRootTasks(rootTask -> {
+ list.add(getRootTaskInfo(rootTask));
});
return list;
}
@@ -2493,8 +2493,8 @@
if (display == null) {
return list;
}
- display.forAllRootTasks(stack -> {
- list.add(getRootTaskInfo(stack));
+ display.forAllRootTasks(rootTask -> {
+ list.add(getRootTaskInfo(rootTask));
});
return list;
}
@@ -2955,8 +2955,8 @@
}
// If {@code r} is already in target display area and its task is the same as the candidate
- // task, the intention should be getting a launch stack for the reusable activity, so we can
- // use the existing stack.
+ // task, the intention should be getting a launch root task for the reusable activity, so we
+ // can use the existing root task.
if (candidateTask != null) {
final TaskDisplayArea attachedTaskDisplayArea = candidateTask.getDisplayArea();
if (attachedTaskDisplayArea == null || attachedTaskDisplayArea == taskDisplayArea) {
@@ -2965,9 +2965,9 @@
// Or the candidate task is already a root task that can be reused by reparenting
// it to the target display.
if (candidateTask.isRootTask()) {
- final Task stack = candidateTask.getRootTask();
- stack.reparent(taskDisplayArea, true /* onTop */);
- return stack;
+ final Task rootTask = candidateTask.getRootTask();
+ rootTask.reparent(taskDisplayArea, true /* onTop */);
+ return rootTask;
}
}
@@ -2984,16 +2984,16 @@
windowingMode = taskDisplayArea.validateWindowingMode(windowingMode, r, candidateTask,
r.getActivityType());
- // Return the topmost valid stack on the display.
+ // Return the topmost valid root task on the display.
final int targetWindowingMode = windowingMode;
- final Task topmostValidStack = taskDisplayArea.getRootTask(stack ->
- isValidLaunchRootTask(stack, r, targetWindowingMode));
- if (topmostValidStack != null) {
- return topmostValidStack;
+ final Task topmostValidRootTask = taskDisplayArea.getRootTask(rootTask ->
+ isValidLaunchRootTask(rootTask, r, targetWindowingMode));
+ if (topmostValidRootTask != null) {
+ return topmostValidRootTask;
}
- // If there is no valid stack on the secondary display area - check if new dynamic stack
- // will do.
+ // If there is no valid root task on the secondary display area - check if new dynamic root
+ // task will do.
if (taskDisplayArea != getDisplayContent(taskDisplayArea.getDisplayId())
.getDefaultTaskDisplayArea()) {
final int activityType =
@@ -3224,8 +3224,8 @@
}
void finishVoiceTask(IVoiceInteractionSession session) {
- forAllRootTasks(stack -> {
- stack.finishVoiceTask(session);
+ forAllRootTasks(rootTask -> {
+ rootTask.finishVoiceTask(session);
});
}
@@ -3284,8 +3284,8 @@
boolean allResumedActivitiesVisible() {
boolean[] foundResumed = {false};
- final boolean foundInvisibleResumedActivity = forAllRootTasks(stack -> {
- final ActivityRecord r = stack.getResumedActivity();
+ final boolean foundInvisibleResumedActivity = forAllRootTasks(rootTask -> {
+ final ActivityRecord r = rootTask.getResumedActivity();
if (r != null) {
if (!r.nowVisible) {
return true;
@@ -3529,9 +3529,9 @@
}
} else {
final ArrayList<ActivityRecord> activities = new ArrayList<>();
- forAllRootTasks(stack -> {
- if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) {
- activities.addAll(stack.getDumpActivitiesLocked(name));
+ forAllRootTasks(rootTask -> {
+ if (!dumpVisibleStacksOnly || rootTask.shouldBeVisible(null)) {
+ activities.addAll(rootTask.getDumpActivitiesLocked(name));
}
});
return activities;
@@ -3581,11 +3581,11 @@
pw.print("Display #");
pw.print(displayContent.mDisplayId);
pw.println(" (activities from top to bottom):");
- displayContent.forAllRootTasks(stack -> {
+ displayContent.forAllRootTasks(rootTask -> {
if (needSep[0]) {
pw.println();
}
- needSep[0] = stack.dump(fd, pw, dumpAll, dumpClient, dumpPackage, false);
+ needSep[0] = rootTask.dump(fd, pw, dumpAll, dumpClient, dumpPackage, false);
printed[0] |= needSep[0];
});
displayContent.forAllTaskDisplayAreas(taskDisplayArea -> {
diff --git a/services/core/java/com/android/server/wm/SnapshotStartingData.java b/services/core/java/com/android/server/wm/SnapshotStartingData.java
index 6ad3f15..2124ed6 100644
--- a/services/core/java/com/android/server/wm/SnapshotStartingData.java
+++ b/services/core/java/com/android/server/wm/SnapshotStartingData.java
@@ -28,14 +28,15 @@
private final WindowManagerService mService;
private final TaskSnapshot mSnapshot;
- SnapshotStartingData(WindowManagerService service, TaskSnapshot snapshot) {
- super(service);
+ SnapshotStartingData(WindowManagerService service, TaskSnapshot snapshot, int typeParams) {
+ super(service, typeParams);
mService = service;
mSnapshot = snapshot;
}
@Override
StartingSurface createStartingSurface(ActivityRecord activity) {
- return mService.mTaskSnapshotController.createStartingSurface(activity, mSnapshot);
+ return mService.mStartingSurfaceController.createTaskSnapshotSurface(activity,
+ mSnapshot);
}
}
diff --git a/services/core/java/com/android/server/wm/SplashScreenStartingData.java b/services/core/java/com/android/server/wm/SplashScreenStartingData.java
index 50a101d..185a317 100644
--- a/services/core/java/com/android/server/wm/SplashScreenStartingData.java
+++ b/services/core/java/com/android/server/wm/SplashScreenStartingData.java
@@ -38,8 +38,8 @@
SplashScreenStartingData(WindowManagerService service, String pkg, int theme,
CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon,
- int logo, int windowFlags, Configuration mergedOverrideConfiguration) {
- super(service);
+ int logo, int windowFlags, Configuration mergedOverrideConfiguration, int typeParams) {
+ super(service, typeParams);
mPkg = pkg;
mTheme = theme;
mCompatInfo = compatInfo;
diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java
index 2e6e777..a5bd797 100644
--- a/services/core/java/com/android/server/wm/StartingData.java
+++ b/services/core/java/com/android/server/wm/StartingData.java
@@ -24,9 +24,11 @@
public abstract class StartingData {
protected final WindowManagerService mService;
+ protected final int mTypeParams;
- protected StartingData(WindowManagerService service) {
+ protected StartingData(WindowManagerService service, int typeParams) {
mService = service;
+ mTypeParams = typeParams;
}
/**
diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java
index 6d7ddf6..94e14dd 100644
--- a/services/core/java/com/android/server/wm/StartingSurfaceController.java
+++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java
@@ -16,9 +16,20 @@
package com.android.server.wm;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
+
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.os.SystemProperties;
+import android.util.Slog;
+import android.window.TaskSnapshot;
import com.android.server.policy.WindowManagerPolicy.StartingSurface;
@@ -26,7 +37,8 @@
* Managing to create and release a starting window surface.
*/
public class StartingSurfaceController {
-
+ private static final String TAG = TAG_WITH_CLASS_NAME
+ ? StartingSurfaceController.class.getSimpleName() : TAG_WM;
/** Set to {@code true} to enable shell starting surface drawer. */
private static final boolean DEBUG_ENABLE_SHELL_DRAWER =
SystemProperties.getBoolean("persist.debug.shell_starting_surface", false);
@@ -49,15 +61,79 @@
final Task task = activity.getTask();
if (task != null && mService.mAtmService.mTaskOrganizerController.addStartingWindow(task,
activity.token)) {
- return new SplashScreenContainerSurface(task);
+ return new ShellStartingSurface(task);
}
return null;
}
- private final class SplashScreenContainerSurface implements StartingSurface {
+ int makeStartingWindowTypeParameter(boolean newTask, boolean taskSwitch,
+ boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated) {
+ int parameter = 0;
+ if (newTask) {
+ parameter |= TYPE_PARAMETER_NEW_TASK;
+ }
+ if (taskSwitch) {
+ parameter |= TYPE_PARAMETER_TASK_SWITCH;
+ }
+ if (processRunning) {
+ parameter |= TYPE_PARAMETER_PROCESS_RUNNING;
+ }
+ if (allowTaskSnapshot) {
+ parameter |= TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
+ }
+ if (activityCreated) {
+ parameter |= TYPE_PARAMETER_ACTIVITY_CREATED;
+ }
+ return parameter;
+ }
+
+ StartingSurface createTaskSnapshotSurface(ActivityRecord activity, TaskSnapshot taskSnapshot) {
+ final WindowState topFullscreenOpaqueWindow;
+ final Task task;
+ synchronized (mService.mGlobalLock) {
+ final WindowState mainWindow = activity.findMainWindow();
+ task = activity.getTask();
+ if (task == null) {
+ Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find task for activity="
+ + activity);
+ return null;
+ }
+ final ActivityRecord topFullscreenActivity =
+ activity.getTask().getTopFullscreenActivity();
+ if (topFullscreenActivity == null) {
+ Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find top fullscreen for task="
+ + task);
+ return null;
+ }
+ topFullscreenOpaqueWindow = topFullscreenActivity.getTopFullscreenOpaqueWindow();
+ if (mainWindow == null || topFullscreenOpaqueWindow == null) {
+ Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for activity="
+ + activity);
+ return null;
+ }
+ if (topFullscreenActivity.getWindowConfiguration().getRotation()
+ != taskSnapshot.getRotation()) {
+ // The snapshot should have been checked by ActivityRecord#isSnapshotCompatible
+ // that the activity will be updated to the same rotation as the snapshot. Since
+ // the transition is not started yet, fixed rotation transform needs to be applied
+ // earlier to make the snapshot show in a rotated container.
+ activity.mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(
+ topFullscreenActivity, false /* checkOpening */);
+ }
+ }
+ if (!DEBUG_ENABLE_SHELL_DRAWER) {
+ return mService.mTaskSnapshotController
+ .createStartingSurface(activity, taskSnapshot);
+ }
+ mService.mAtmService.mTaskOrganizerController.addStartingWindow(task, activity.token);
+ return new ShellStartingSurface(task);
+ }
+
+
+ private final class ShellStartingSurface implements StartingSurface {
private final Task mTask;
- SplashScreenContainerSurface(Task task) {
+ ShellStartingSurface(Task task) {
mTask = task;
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index abd51ee..79a32e4 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -156,7 +156,6 @@
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.TaskDescription;
-import android.window.TaskSnapshot;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.AppGlobals;
@@ -207,6 +206,8 @@
import android.view.WindowManager;
import android.view.WindowManager.TransitionOldType;
import android.window.ITaskOrganizer;
+import android.window.StartingWindowInfo;
+import android.window.TaskSnapshot;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -4145,6 +4146,34 @@
return info;
}
+ StartingWindowInfo getStartingWindowInfo() {
+ final StartingWindowInfo info = new StartingWindowInfo();
+ info.taskInfo = getTaskInfo();
+
+ final ActivityRecord topActivity = getTopMostActivity();
+ if (topActivity != null) {
+ info.startingWindowTypeParameter =
+ topActivity.mStartingData != null
+ ? topActivity.mStartingData.mTypeParams
+ : 0;
+ final WindowState mainWindow = topActivity.findMainWindow();
+ if (mainWindow != null) {
+ info.mainWindowLayoutParams = mainWindow.getAttrs();
+ }
+ }
+ final ActivityRecord topFullscreenActivity = getTopFullscreenActivity();
+ if (topFullscreenActivity != null) {
+ final WindowState topFullscreenOpaqueWindow =
+ topFullscreenActivity.getTopFullscreenOpaqueWindow();
+ if (topFullscreenOpaqueWindow != null) {
+ info.topOpaqueWindowInsetsState =
+ topFullscreenOpaqueWindow.getInsetsStateWithVisibilityOverride();
+ info.topOpaqueWindowLayoutParams = topFullscreenOpaqueWindow.getAttrs();
+ }
+ }
+ return info;
+ }
+
boolean isTaskId(int taskId) {
return mTaskId == taskId;
}
@@ -4955,6 +4984,7 @@
}
} else {
// No longer managed by any organizer.
+ mTaskAppearedSent = false;
setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, false /* set */);
if (mCreatedByOrganizer) {
removeImmediately();
@@ -4979,6 +5009,11 @@
* @return {@code true} if task organizer changed.
*/
boolean updateTaskOrganizerState(boolean forceUpdate, boolean skipTaskAppeared) {
+ if (getSurfaceControl() == null) {
+ // Can't call onTaskAppeared without a surfacecontrol, so defer this until after one
+ // is created.
+ return false;
+ }
if (!canBeOrganized()) {
return setTaskOrganizer(null);
}
@@ -4988,10 +5023,6 @@
final ITaskOrganizer organizer = controller.getTaskOrganizer(windowingMode);
if (!forceUpdate && mTaskOrganizer == organizer) {
return false;
- } else if (organizer != null && getSurfaceControl() == null) {
- // Can't call onTaskAppeared without a surfacecontrol, so defer this until after one
- // is created.
- return false;
}
return setTaskOrganizer(organizer, skipTaskAppeared);
}
@@ -5318,20 +5349,19 @@
final TaskDisplayArea taskDisplayArea = getDisplayArea();
if (inSplitScreenSecondaryWindowingMode()) {
- // If the stack is in split-screen secondary mode, we need to make sure we move the
- // primary split-screen stack forward in the case it is currently behind a fullscreen
- // stack so both halves of the split-screen appear on-top and the fullscreen stack isn't
- // cutting between them.
+ // If the root task is in split-screen secondary mode, we need to make sure we move the
+ // primary split-screen root task forward in the case it is currently behind a
+ // fullscreen root task so both halves of the split-screen appear on-top and the
+ // fullscreen root task isn't cutting between them.
// TODO(b/70677280): This is a workaround until we can fix as part of b/70677280.
- final Task topFullScreenStack =
+ final Task topFullScreenRootTask =
taskDisplayArea.getTopRootTaskInWindowingMode(WINDOWING_MODE_FULLSCREEN);
- if (topFullScreenStack != null) {
- final Task primarySplitScreenStack =
+ if (topFullScreenRootTask != null) {
+ final Task primarySplitScreenRootTask =
taskDisplayArea.getRootSplitScreenPrimaryTask();
- if (primarySplitScreenStack != null
- && taskDisplayArea.getIndexOf(topFullScreenStack)
- > taskDisplayArea.getIndexOf(primarySplitScreenStack)) {
- primarySplitScreenStack.moveToFront(reason + " splitScreenToTop");
+ if (primarySplitScreenRootTask != null
+ && topFullScreenRootTask.compareTo(primarySplitScreenRootTask) > 0) {
+ primarySplitScreenRootTask.moveToFront(reason + " splitScreenToTop");
}
}
}
@@ -5746,7 +5776,7 @@
}
/**
- * @return {@code true} if this is the focused stack on its current display, {@code false}
+ * @return {@code true} if this is the focused root task on its current display, {@code false}
* otherwise.
*/
boolean isFocusedStackOnDisplay() {
@@ -6698,18 +6728,21 @@
});
}
- /** @return true if the stack behind this one is a standard activity type. */
- private boolean inFrontOfStandardStack() {
+ /** @return true if the root task behind this one is a standard activity type. */
+ private boolean inFrontOfStandardRootTask() {
final TaskDisplayArea taskDisplayArea = getDisplayArea();
if (taskDisplayArea == null) {
return false;
}
- final int index = taskDisplayArea.getIndexOf(this);
+ final int index = taskDisplayArea.getTaskIndexOf(this);
if (index == 0) {
return false;
}
- final Task stackBehind = taskDisplayArea.getChildAt(index - 1);
- return stackBehind.isActivityTypeStandard();
+ final int[] indexCount = new int[1];
+ final Task rootTaskBehind = taskDisplayArea.getRootTask(
+ // From bottom to top, find the one behind this Task.
+ task -> ++indexCount[0] == index, false /* traverseTopToBottom */);
+ return rootTaskBehind.isActivityTypeStandard();
}
boolean shouldUpRecreateTaskLocked(ActivityRecord srec, String destAffinity) {
@@ -6730,7 +6763,7 @@
if (srec.isRootOfTask() && task.getBaseIntent() != null
&& task.getBaseIntent().isDocument()) {
// Okay, this activity is at the root of its task. What to do, what to do...
- if (!inFrontOfStandardStack()) {
+ if (!inFrontOfStandardRootTask()) {
// Finishing won't return to an application, so we need to recreate.
return true;
}
@@ -7631,7 +7664,7 @@
void dispatchTaskInfoChangedIfNeeded(boolean force) {
if (isOrganized()) {
- mAtmService.mTaskOrganizerController.onTaskInfoChanged(this, force);
+ mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, force);
}
}
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 7fed840..866abbd 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -71,8 +71,10 @@
/**
* {@link DisplayArea} that represents a section of a screen that contains app window containers.
+ *
+ * The children can be either {@link Task} or {@link TaskDisplayArea}.
*/
-final class TaskDisplayArea extends DisplayArea<Task> {
+final class TaskDisplayArea extends DisplayArea<WindowContainer> {
DisplayContent mDisplayContent;
@@ -106,9 +108,9 @@
// TODO(b/159029784): Remove when getStack() behavior is cleaned-up
private Task mRootRecentsTask;
- private final ArrayList<Task> mTmpAlwaysOnTopRootTasks = new ArrayList<>();
- private final ArrayList<Task> mTmpNormalRootTasks = new ArrayList<>();
- private final ArrayList<Task> mTmpHomeRootTasks = new ArrayList<>();
+ private final ArrayList<WindowContainer> mTmpAlwaysOnTopChildren = new ArrayList<>();
+ private final ArrayList<WindowContainer> mTmpNormalChildren = new ArrayList<>();
+ private final ArrayList<WindowContainer> mTmpHomeChildren = new ArrayList<>();
private final IntArray mTmpNeedsZBoostIndexes = new IntArray();
private int mTmpLayerForSplitScreenDividerAnchor;
private int mTmpLayerForAnimationLayer;
@@ -179,9 +181,10 @@
}
/**
- * Returns the topmost stack on the display that is compatible with the input windowing mode
- * and activity type. Null is no compatible stack on the display.
+ * Returns the topmost root task on the display that is compatible with the input windowing mode
+ * and activity type. Null is no compatible root task on the display.
*/
+ @Nullable
Task getRootTask(int windowingMode, int activityType) {
if (activityType == ACTIVITY_TYPE_HOME) {
return mRootHomeTask;
@@ -193,30 +196,48 @@
} else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
return mRootSplitScreenPrimaryTask;
}
- for (int i = getChildCount() - 1; i >= 0; --i) {
- final Task stack = getChildAt(i);
+ return getRootTask(rootTask -> {
if (activityType == ACTIVITY_TYPE_UNDEFINED
- && windowingMode == stack.getWindowingMode()) {
- // Passing in undefined type means we want to match the topmost stack with the
+ && windowingMode == rootTask.getWindowingMode()) {
+ // Passing in undefined type means we want to match the topmost root task with the
// windowing mode.
- return stack;
+ return true;
}
- if (stack.isCompatible(windowingMode, activityType)) {
- return stack;
- }
- }
- return null;
+ return rootTask.isCompatible(windowingMode, activityType);
+ });
}
@VisibleForTesting
Task getTopRootTask() {
- final int count = getChildCount();
- return count > 0 ? getChildAt(count - 1) : null;
+ return getRootTask(t -> true);
}
- // TODO: Figure-out a way to remove since it might be a source of confusion.
- int getIndexOf(Task task) {
- return mChildren.indexOf(task);
+ // TODO(b/175832855): Figure-out a way to remove since it might be a source of confusion.
+ /**
+ * Gets the order of the given {@link Task} as its z-order in the hierarchy below this TDA.
+ * The Task can be a direct child of a child TaskDisplayArea. {@code -1} if not found.
+ */
+ int getTaskIndexOf(Task task) {
+ int index = 0;
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ final WindowContainer wc = getChildAt(i);
+ if (wc.asTask() != null) {
+ if (wc.asTask() == task) {
+ return index;
+ }
+ index++;
+ } else {
+ final TaskDisplayArea tda = wc.asTaskDisplayArea();
+ final int subIndex = tda.getTaskIndexOf(task);
+ if (subIndex > -1) {
+ return index + subIndex;
+ } else {
+ index += tda.getRootTaskCount();
+ }
+ }
+ }
+ return -1;
}
@Nullable
@@ -238,9 +259,11 @@
}
Task getRootSplitScreenSecondaryTask() {
+ // Only check the direct child Task for now, since the primary is also a direct child Task.
for (int i = mChildren.size() - 1; i >= 0; --i) {
- if (mChildren.get(i).inSplitScreenSecondaryWindowingMode()) {
- return mChildren.get(i);
+ final Task task = mChildren.get(i).asTask();
+ if (task != null && task.inSplitScreenSecondaryWindowingMode()) {
+ return task;
}
}
return null;
@@ -323,7 +346,22 @@
}
@Override
- void addChild(Task task, int position) {
+ void addChild(WindowContainer child, int position) {
+ if (child.asTaskDisplayArea() != null) {
+ if (DEBUG_ROOT_TASK) {
+ Slog.d(TAG_WM, "Set TaskDisplayArea=" + child + " on taskDisplayArea=" + this);
+ }
+ super.addChild(child, position);
+ } else if (child.asTask() != null) {
+ addChildTask(child.asTask(), position);
+ } else {
+ throw new IllegalArgumentException(
+ "TaskDisplayArea can only add Task and TaskDisplayArea, but found "
+ + child);
+ }
+ }
+
+ private void addChildTask(Task task, int position) {
if (DEBUG_ROOT_TASK) Slog.d(TAG_WM, "Set task=" + task + " on taskDisplayArea=" + this);
addRootTaskReferenceIfNeeded(task);
@@ -335,11 +373,23 @@
}
@Override
- protected void removeChild(Task stack) {
- super.removeChild(stack);
- onRootTaskRemoved(stack);
+ protected void removeChild(WindowContainer child) {
+ if (child.asTaskDisplayArea() != null) {
+ super.removeChild(child);
+ } else if (child.asTask() != null) {
+ removeChildTask(child.asTask());
+ } else {
+ throw new IllegalArgumentException(
+ "TaskDisplayArea can only remove Task and TaskDisplayArea, but found "
+ + child);
+ }
+ }
+
+ private void removeChildTask(Task task) {
+ super.removeChild(task);
+ onRootTaskRemoved(task);
mAtmService.updateSleepIfNeededLocked();
- removeRootTaskReferenceIfNeeded(stack);
+ removeRootTaskReferenceIfNeeded(task);
}
@Override
@@ -349,21 +399,33 @@
}
@Override
- void positionChildAt(int position, Task child, boolean includingParents) {
+ void positionChildAt(int position, WindowContainer child, boolean includingParents) {
+ if (child.asTaskDisplayArea() != null) {
+ super.positionChildAt(position, child, includingParents);
+ } else if (child.asTask() != null) {
+ positionChildTaskAt(position, child.asTask(), includingParents);
+ } else {
+ throw new IllegalArgumentException(
+ "TaskDisplayArea can only position Task and TaskDisplayArea, but found "
+ + child);
+ }
+ }
+
+ private void positionChildTaskAt(int position, Task child, boolean includingParents) {
final boolean moveToTop = position >= getChildCount() - 1;
final boolean moveToBottom = position <= 0;
final int oldPosition = mChildren.indexOf(child);
if (child.getWindowConfiguration().isAlwaysOnTop() && !moveToTop) {
- // This stack is always-on-top, override the default behavior.
- Slog.w(TAG_WM, "Ignoring move of always-on-top stack=" + this + " to bottom");
+ // This root task is always-on-top, override the default behavior.
+ Slog.w(TAG_WM, "Ignoring move of always-on-top root task=" + this + " to bottom");
// Moving to its current position, as we must call super but we don't want to
// perform any meaningful action.
super.positionChildAt(oldPosition, child, false /* includingParents */);
return;
}
- // We don't allow untrusted display to top when task stack moves to top,
+ // We don't allow untrusted display to top when root task moves to top,
// until user tapping this display to change display position as top intentionally.
if (!mDisplayContent.isTrusted() && !getParent().isOnTop()) {
includingParents = false;
@@ -432,41 +494,78 @@
@Override
boolean forAllTaskDisplayAreas(Function<TaskDisplayArea, Boolean> callback,
boolean traverseTopToBottom) {
- return callback.apply(this);
+ // Apply the callback to all TDAs at or below this container. If the callback returns true,
+ // stop early.
+ if (traverseTopToBottom) {
+ // When it is top to bottom, run on child TDA first as they are on top of the parent.
+ return super.forAllTaskDisplayAreas(callback, traverseTopToBottom)
+ || callback.apply(this);
+ }
+ return callback.apply(this) || super.forAllTaskDisplayAreas(callback, traverseTopToBottom);
}
@Override
void forAllTaskDisplayAreas(Consumer<TaskDisplayArea> callback, boolean traverseTopToBottom) {
- callback.accept(this);
+ if (traverseTopToBottom) {
+ super.forAllTaskDisplayAreas(callback, traverseTopToBottom);
+ callback.accept(this);
+ } else {
+ callback.accept(this);
+ super.forAllTaskDisplayAreas(callback, traverseTopToBottom);
+ }
}
@Nullable
@Override
<R> R reduceOnAllTaskDisplayAreas(BiFunction<TaskDisplayArea, R, R> accumulator,
@Nullable R initValue, boolean traverseTopToBottom) {
- return accumulator.apply(this, initValue);
+ if (traverseTopToBottom) {
+ final R result =
+ super.reduceOnAllTaskDisplayAreas(accumulator, initValue, traverseTopToBottom);
+ return accumulator.apply(this, result);
+ } else {
+ final R result = accumulator.apply(this, initValue);
+ return super.reduceOnAllTaskDisplayAreas(accumulator, result, traverseTopToBottom);
+
+ }
}
@Nullable
@Override
<R> R getItemFromTaskDisplayAreas(Function<TaskDisplayArea, R> callback,
boolean traverseTopToBottom) {
- return callback.apply(this);
+ if (traverseTopToBottom) {
+ final R item = super.getItemFromTaskDisplayAreas(callback, traverseTopToBottom);
+ return item != null ? item : callback.apply(this);
+ } else {
+ final R item = callback.apply(this);
+ return item != null
+ ? item
+ : super.getItemFromTaskDisplayAreas(callback, traverseTopToBottom);
+ }
}
/**
- * Assigns a priority number to stack types. This priority defines an order between the types
- * of stacks that are added to the task display area.
+ * Assigns a priority number to root task types. This priority defines an order between the
+ * types of root task that are added to the task display area.
*
- * Higher priority number indicates that the stack should have a higher z-order.
+ * Higher priority number indicates that the root task should have a higher z-order.
*
- * @return the priority of the stack
+ * For child {@link TaskDisplayArea}, it will be the priority of its top child.
+ *
+ * @return the priority of the root task
*/
- private int getPriority(Task stack) {
- if (mWmService.mAssistantOnTopOfDream && stack.isActivityTypeAssistant()) return 4;
- if (stack.isActivityTypeDream()) return 3;
- if (stack.inPinnedWindowingMode()) return 2;
- if (stack.isAlwaysOnTop()) return 1;
+ private int getPriority(WindowContainer child) {
+ final TaskDisplayArea tda = child.asTaskDisplayArea();
+ if (tda != null) {
+ // Use the top child priority as the TaskDisplayArea priority.
+ return tda.getPriority(tda.getTopChild());
+ }
+ final Task rootTask = child.asTask();
+ if (mWmService.mAssistantOnTopOfDream && rootTask.isActivityTypeAssistant()) return 4;
+ if (rootTask.isActivityTypeDream()) return 3;
+ if (rootTask.inPinnedWindowingMode()) return 2;
+ if (rootTask.isAlwaysOnTop()) return 1;
return 0;
}
@@ -481,10 +580,12 @@
}
if (rootTask.isAlwaysOnTop()) {
- // Since a stack could be repositioned while still being one of the children, we check
- // if this always-on-top stack already exists and if so, set the minPosition to its
- // previous position.
- final int currentIndex = getIndexOf(rootTask);
+ // Since a root task could be repositioned while still being one of the children, we
+ // check if this always-on-top root task already exists and if so, set the minPosition
+ // to its previous position.
+ // Use mChildren.indexOf instead of getTaskIndexOf because we need to place the rootTask
+ // as a direct child.
+ final int currentIndex = mChildren.indexOf(rootTask);
if (currentIndex > minPosition) {
minPosition = currentIndex;
}
@@ -494,9 +595,9 @@
private int findMaxPositionForRootTask(Task rootTask) {
for (int i = mChildren.size() - 1; i >= 0; --i) {
- final Task curr = mChildren.get(i);
- // Since a stack could be repositioned while still being one of the children, we check
- // if 'curr' is the same stack and skip it if so
+ final WindowContainer curr = mChildren.get(i);
+ // Since a root task could be repositioned while still being one of the children, we
+ // check if 'curr' is the same root task and skip it if so
final boolean sameRootTask = curr == rootTask;
if (getPriority(curr) <= getPriority(rootTask) && !sameRootTask) {
return i;
@@ -506,29 +607,29 @@
}
/**
- * When stack is added or repositioned, find a proper position for it.
+ * When root task is added or repositioned, find a proper position for it.
*
* The order is defined as:
* - Dream is on top of everything
* - PiP is directly below the Dream
- * - always-on-top stacks are directly below PiP; new always-on-top stacks are added above
- * existing ones
- * - other non-always-on-top stacks come directly below always-on-top stacks; new
- * non-always-on-top stacks are added directly below always-on-top stacks and above existing
- * non-always-on-top stacks
+ * - always-on-top root tasks are directly below PiP; new always-on-top root tasks are added
+ * above existing ones
+ * - other non-always-on-top root tasks come directly below always-on-top root tasks; new
+ * non-always-on-top root tasks are added directly below always-on-top root tasks and above
+ * existing non-always-on-top root tasks
* - if {@link #mAssistantOnTopOfDream} is enabled, then Assistant is on top of everything
- * (including the Dream); otherwise, it is a normal non-always-on-top stack
+ * (including the Dream); otherwise, it is a normal non-always-on-top root task
*
* @param requestedPosition Position requested by caller.
* @param rootTask Root task to be added or positioned.
- * @param adding Flag indicates whether we're adding a new stack or positioning an
- * existing.
- * @return The proper position for the stack.
+ * @param adding Flag indicates whether we're adding a new root task or positioning
+ * an existing.
+ * @return The proper position for the root task.
*/
private int findPositionForRootTask(int requestedPosition, Task rootTask, boolean adding) {
- // The max possible position we can insert the stack at.
+ // The max possible position we can insert the root task at.
int maxPosition = findMaxPositionForRootTask(rootTask);
- // The min possible position we can insert the stack at.
+ // The min possible position we can insert the root task at.
int minPosition = findMinPositionForRootTask(rootTask);
// Cap the requested position to something reasonable for the previous position check
@@ -547,8 +648,8 @@
// The positions we calculated above (maxPosition, minPosition) do not take into
// consideration the following edge cases.
// 1) We need to adjust the position depending on the value "adding".
- // 2) When we are moving a stack to another position, we also need to adjust the
- // position depending on whether the stack is moving to a higher or lower position.
+ // 2) When we are moving a root task to another position, we also need to adjust the
+ // position depending on whether the root task is moving to a higher or lower position.
if ((targetPosition != requestedPosition) && (adding || targetPosition < prevPosition)) {
targetPosition++;
}
@@ -579,13 +680,19 @@
private boolean forAllExitingAppTokenWindows(ToBooleanFunction<WindowState> callback,
boolean traverseTopToBottom) {
- // For legacy reasons we process the TaskStack.mExitingActivities first here before the
+ // For legacy reasons we process the RootTask.mExitingActivities first here before the
// app tokens.
// TODO: Investigate if we need to continue to do this or if we can just process them
// in-order.
if (traverseTopToBottom) {
for (int i = mChildren.size() - 1; i >= 0; --i) {
- final List<ActivityRecord> activities = mChildren.get(i).mExitingActivities;
+ // Only run on those of direct Task child, because child TaskDisplayArea has run on
+ // its child in #forAllWindows()
+ if (mChildren.get(i).asTask() == null) {
+ continue;
+ }
+ final List<ActivityRecord> activities =
+ mChildren.get(i).asTask().mExitingActivities;
for (int j = activities.size() - 1; j >= 0; --j) {
if (activities.get(j).forAllWindowsUnchecked(callback,
traverseTopToBottom)) {
@@ -596,7 +703,13 @@
} else {
final int count = mChildren.size();
for (int i = 0; i < count; ++i) {
- final List<ActivityRecord> activities = mChildren.get(i).mExitingActivities;
+ // Only run on those of direct Task child, because child TaskDisplayArea has run on
+ // its child in #forAllWindows()
+ if (mChildren.get(i).asTask() == null) {
+ continue;
+ }
+ final List<ActivityRecord> activities =
+ mChildren.get(i).asTask().mExitingActivities;
final int appTokensCount = activities.size();
for (int j = 0; j < appTokensCount; j++) {
if (activities.get(j).forAllWindowsUnchecked(callback,
@@ -612,9 +725,18 @@
@Override
int getOrientation(int candidate) {
mLastOrientationSource = null;
- if (!canSpecifyOrientation()) {
+ if (mIgnoreOrientationRequest) {
return SCREEN_ORIENTATION_UNSET;
}
+ if (!canSpecifyOrientation()) {
+ // We only respect orientation of the focused TDA, which can be a child of this TDA.
+ return reduceOnAllTaskDisplayAreas((taskDisplayArea, orientation) -> {
+ if (taskDisplayArea == this || orientation != SCREEN_ORIENTATION_UNSET) {
+ return orientation;
+ }
+ return taskDisplayArea.getOrientation(candidate);
+ }, SCREEN_ORIENTATION_UNSET);
+ }
if (isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
// Apps and their containers are not allowed to specify an orientation while using
@@ -671,8 +793,7 @@
assignRootTaskOrdering(t);
for (int i = 0; i < mChildren.size(); i++) {
- final Task s = mChildren.get(i);
- s.assignChildLayers(t);
+ mChildren.get(i).assignChildLayers(t);
}
}
@@ -680,33 +801,49 @@
if (getParent() == null) {
return;
}
- mTmpAlwaysOnTopRootTasks.clear();
- mTmpHomeRootTasks.clear();
- mTmpNormalRootTasks.clear();
+ mTmpAlwaysOnTopChildren.clear();
+ mTmpHomeChildren.clear();
+ mTmpNormalChildren.clear();
for (int i = 0; i < mChildren.size(); ++i) {
- final Task s = mChildren.get(i);
- if (s.isAlwaysOnTop()) {
- mTmpAlwaysOnTopRootTasks.add(s);
- } else if (s.isActivityTypeHome()) {
- mTmpHomeRootTasks.add(s);
+ final WindowContainer child = mChildren.get(i);
+ final TaskDisplayArea childTda = child.asTaskDisplayArea();
+ if (childTda != null) {
+ final Task childTdaTopRootTask = childTda.getTopRootTask();
+ if (childTdaTopRootTask == null) {
+ mTmpNormalChildren.add(childTda);
+ } else if (childTdaTopRootTask.isAlwaysOnTop()) {
+ mTmpAlwaysOnTopChildren.add(childTda);
+ } else if (childTdaTopRootTask.isActivityTypeHome()) {
+ mTmpHomeChildren.add(childTda);
+ } else {
+ mTmpNormalChildren.add(childTda);
+ }
+ continue;
+ }
+
+ final Task childTask = child.asTask();
+ if (childTask.isAlwaysOnTop()) {
+ mTmpAlwaysOnTopChildren.add(childTask);
+ } else if (childTask.isActivityTypeHome()) {
+ mTmpHomeChildren.add(childTask);
} else {
- mTmpNormalRootTasks.add(s);
+ mTmpNormalChildren.add(childTask);
}
}
int layer = 0;
// Place home stacks to the bottom.
- layer = adjustRootTaskLayer(t, mTmpHomeRootTasks, layer, false /* normalStacks */);
+ layer = adjustRootTaskLayer(t, mTmpHomeChildren, layer, false /* normalRootTasks */);
// The home animation layer is between the home stacks and the normal stacks.
final int layerForHomeAnimationLayer = layer++;
mTmpLayerForSplitScreenDividerAnchor = layer++;
mTmpLayerForAnimationLayer = layer++;
- layer = adjustRootTaskLayer(t, mTmpNormalRootTasks, layer, true /* normalStacks */);
+ layer = adjustRootTaskLayer(t, mTmpNormalChildren, layer, true /* normalRootTasks */);
// The boosted animation layer is between the normal stacks and the always on top
// stacks.
final int layerForBoostedAnimationLayer = layer++;
- adjustRootTaskLayer(t, mTmpAlwaysOnTopRootTasks, layer, false /* normalStacks */);
+ adjustRootTaskLayer(t, mTmpAlwaysOnTopChildren, layer, false /* normalRootTasks */);
t.setLayer(mHomeAppAnimationLayer, layerForHomeAnimationLayer);
t.setLayer(mAppAnimationLayer, mTmpLayerForAnimationLayer);
@@ -714,13 +851,14 @@
t.setLayer(mBoostedAppAnimationLayer, layerForBoostedAnimationLayer);
}
- private int adjustNormalRootTaskLayer(Task s, int layer) {
- if (s.inSplitScreenWindowingMode()) {
+ private int adjustNormalRootTaskLayer(WindowContainer child, int layer) {
+ if (child.asTask() != null && child.inSplitScreenWindowingMode()) {
// The split screen divider anchor is located above the split screen window.
mTmpLayerForSplitScreenDividerAnchor = layer++;
}
- if (s.isAnimatingByRecents() || s.isAppTransitioning()) {
- // The animation layer is located above the highest animating stack and no
+ if ((child.asTask() != null && child.asTask().isAnimatingByRecents())
+ || child.isAppTransitioning()) {
+ // The animation layer is located above the highest animating root task and no
// higher.
mTmpLayerForAnimationLayer = layer++;
}
@@ -728,23 +866,30 @@
}
/**
- * Adjusts the layer of the stack which belongs to the same group.
- * Note that there are three stack groups: home stacks, always on top stacks, and normal stacks.
+ * Adjusts the layer of the root task which belongs to the same group.
+ * Note that there are three root task groups: home rootTasks, always on top rootTasks, and
+ * normal rootTasks.
*
- * @param startLayer The beginning layer of this group of stacks.
- * @param normalStacks Set {@code true} if this group is neither home nor always on top.
+ * @param startLayer The beginning layer of this group of rootTasks.
+ * @param normalRootTasks Set {@code true} if this group is neither home nor always on top.
* @return The adjusted layer value.
*/
- private int adjustRootTaskLayer(SurfaceControl.Transaction t, ArrayList<Task> stacks,
- int startLayer, boolean normalStacks) {
+ private int adjustRootTaskLayer(SurfaceControl.Transaction t,
+ ArrayList<WindowContainer> children, int startLayer, boolean normalRootTasks) {
mTmpNeedsZBoostIndexes.clear();
- final int stackSize = stacks.size();
- for (int i = 0; i < stackSize; i++) {
- final Task stack = stacks.get(i);
- if (!stack.needsZBoost()) {
- stack.assignLayer(t, startLayer++);
- if (normalStacks) {
- startLayer = adjustNormalRootTaskLayer(stack, startLayer);
+ final int childCount = children.size();
+ for (int i = 0; i < childCount; i++) {
+ final WindowContainer child = children.get(i);
+ final TaskDisplayArea childTda = child.asTaskDisplayArea();
+
+ boolean childNeedsZBoost = childTda != null
+ ? childTda.childrenNeedZBoost()
+ : child.needsZBoost();
+
+ if (!childNeedsZBoost) {
+ child.assignLayer(t, startLayer++);
+ if (normalRootTasks) {
+ startLayer = adjustNormalRootTaskLayer(child, startLayer);
}
} else {
mTmpNeedsZBoostIndexes.add(i);
@@ -753,15 +898,23 @@
final int zBoostSize = mTmpNeedsZBoostIndexes.size();
for (int i = 0; i < zBoostSize; i++) {
- final Task stack = stacks.get(mTmpNeedsZBoostIndexes.get(i));
- stack.assignLayer(t, startLayer++);
- if (normalStacks) {
- startLayer = adjustNormalRootTaskLayer(stack, startLayer);
+ final WindowContainer child = children.get(mTmpNeedsZBoostIndexes.get(i));
+ child.assignLayer(t, startLayer++);
+ if (normalRootTasks) {
+ startLayer = adjustNormalRootTaskLayer(child, startLayer);
}
}
return startLayer;
}
+ private boolean childrenNeedZBoost() {
+ final boolean[] needsZBoost = new boolean[1];
+ forAllRootTasks(task -> {
+ needsZBoost[0] |= task.needsZBoost();
+ });
+ return needsZBoost[0];
+ }
+
@Override
SurfaceControl getAppAnimationLayer(@AnimationLayer int animationLayer) {
switch (animationLayer) {
@@ -1027,15 +1180,25 @@
return null;
}
for (int i = mChildren.size() - 1; i >= 0; --i) {
- final Task t = mChildren.get(i);
- if (!t.mCreatedByOrganizer || t.getRequestedOverrideWindowingMode() != windowingMode) {
+ final WindowContainer child = mChildren.get(i);
+ if (child.asTaskDisplayArea() != null) {
+ final Task t = child.asTaskDisplayArea().updateLaunchRootTask(windowingMode);
+ if (t != null) {
+ return t;
+ }
+ continue;
+ }
+
+ final Task t = mChildren.get(i).asTask();
+ if (t == null || !t.mCreatedByOrganizer
+ || t.getRequestedOverrideWindowingMode() != windowingMode) {
continue;
}
// If not already set, pick a launch root which is not the one we are launching into.
if (mLaunchRootTask == null) {
for (int j = 0, n = mChildren.size(); j < n; ++j) {
- final Task tt = mChildren.get(j);
- if (tt.mCreatedByOrganizer && tt != t) {
+ final Task tt = mChildren.get(j).asTask();
+ if (tt != null && tt.mCreatedByOrganizer && tt != t) {
mLaunchRootTask = tt;
break;
}
@@ -1081,8 +1244,8 @@
}
/**
- * Get the preferred focusable stack in priority. If the preferred stack does not exist, find a
- * focusable and visible stack from the top of stacks in this display.
+ * Get the preferred focusable root task in priority. If the preferred root task does not exist,
+ * find a focusable and visible root task from the top of root tasks in this display.
*/
Task getFocusedRootTask() {
if (mPreferredTopFocusableRootTask != null) {
@@ -1090,9 +1253,18 @@
}
for (int i = mChildren.size() - 1; i >= 0; --i) {
- final Task stack = mChildren.get(i);
- if (stack.isFocusableAndVisible()) {
- return stack;
+ final WindowContainer child = mChildren.get(i);
+ if (child.asTaskDisplayArea() != null) {
+ final Task rootTask = child.asTaskDisplayArea().getFocusedRootTask();
+ if (rootTask != null) {
+ return rootTask;
+ }
+ continue;
+ }
+
+ final Task rootTask = mChildren.get(i).asTask();
+ if (rootTask.isFocusableAndVisible()) {
+ return rootTask;
}
}
@@ -1105,7 +1277,17 @@
Task candidate = null;
for (int i = mChildren.size() - 1; i >= 0; --i) {
- final Task rootTask = mChildren.get(i);
+ final WindowContainer child = mChildren.get(i);
+ if (child.asTaskDisplayArea() != null) {
+ final Task rootTask = child.asTaskDisplayArea()
+ .getNextFocusableRootTask(currentFocus, ignoreCurrent);
+ if (rootTask != null) {
+ return rootTask;
+ }
+ continue;
+ }
+
+ final Task rootTask = mChildren.get(i).asTask();
if (ignoreCurrent && rootTask == currentFocus) {
continue;
}
@@ -1115,18 +1297,19 @@
if (currentWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
&& candidate == null && rootTask.inSplitScreenPrimaryWindowingMode()) {
- // If the currently focused stack is in split-screen secondary we save off the
- // top primary split-screen stack as a candidate for focus because we might
- // prefer focus to move to an other stack to avoid primary split-screen stack
- // overlapping with a fullscreen stack when a fullscreen stack is higher in z
- // than the next split-screen stack. Assistant stack, I am looking at you...
- // We only move the focus to the primary-split screen stack if there isn't a
+ // If the currently focused root task is in split-screen secondary we save off the
+ // top primary split-screen root task as a candidate for focus because we might
+ // prefer focus to move to an other root task to avoid primary split-screen root
+ // task overlapping with a fullscreen root task when a fullscreen root task is
+ // higher in z than the next split-screen root task. Assistant root task, I am
+ // looking at you...
+ // We only move the focus to the primary-split screen root task if there isn't a
// better alternative.
candidate = rootTask;
continue;
}
if (candidate != null && rootTask.inSplitScreenSecondaryWindowingMode()) {
- // Use the candidate stack since we are now at the secondary split-screen.
+ // Use the candidate root task since we are now at the secondary split-screen.
return candidate;
}
return rootTask;
@@ -1135,21 +1318,21 @@
}
ActivityRecord getFocusedActivity() {
- final Task focusedStack = getFocusedRootTask();
- if (focusedStack == null) {
+ final Task focusedRootTask = getFocusedRootTask();
+ if (focusedRootTask == null) {
return null;
}
// TODO(b/111541062): Move this into ActivityStack#getResumedActivity()
- // Check if the focused stack has the resumed activity
- ActivityRecord resumedActivity = focusedStack.getResumedActivity();
+ // Check if the focused root task has the resumed activity
+ ActivityRecord resumedActivity = focusedRootTask.getResumedActivity();
if (resumedActivity == null || resumedActivity.app == null) {
- // If there is no registered resumed activity in the stack or it is not running -
+ // If there is no registered resumed activity in the root task or it is not running -
// try to use previously resumed one.
- resumedActivity = focusedStack.getPausingActivity();
+ resumedActivity = focusedRootTask.getPausingActivity();
if (resumedActivity == null || resumedActivity.app == null) {
// If previously resumed activity doesn't work either - find the topmost running
// activity that can be focused.
- resumedActivity = focusedStack.topRunningActivity(true /* focusableOnly */);
+ resumedActivity = focusedRootTask.topRunningActivity(true /* focusableOnly */);
}
}
return resumedActivity;
@@ -1184,27 +1367,35 @@
}
boolean allResumedActivitiesComplete() {
- for (int stackNdx = mChildren.size() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityRecord r = mChildren.get(stackNdx).getResumedActivity();
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final WindowContainer child = mChildren.get(i);
+ if (child.asTaskDisplayArea() != null) {
+ if (!child.asTaskDisplayArea().allResumedActivitiesComplete()) {
+ return false;
+ }
+ continue;
+ }
+
+ final ActivityRecord r = mChildren.get(i).asTask().getResumedActivity();
if (r != null && !r.isState(RESUMED)) {
return false;
}
}
- final Task currentFocusedStack = getFocusedRootTask();
+ final Task currentFocusedRootTask = getFocusedRootTask();
if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) {
- Slog.d(TAG_ROOT_TASK, "allResumedActivitiesComplete: mLastFocusedStack changing from="
- + mLastFocusedRootTask + " to=" + currentFocusedStack);
+ Slog.d(TAG_ROOT_TASK, "allResumedActivitiesComplete: currentFocusedRootTask "
+ + "changing from=" + mLastFocusedRootTask + " to=" + currentFocusedRootTask);
}
- mLastFocusedRootTask = currentFocusedStack;
+ mLastFocusedRootTask = currentFocusedRootTask;
return true;
}
/**
- * Pause all activities in either all of the stacks or just the back stacks. This is done before
- * resuming a new activity and to make sure that previously active activities are
- * paused in stacks that are no longer visible or in pinned windowing mode. This does not
- * pause activities in visible stacks, so if an activity is launched within the same stack/task,
- * then we should explicitly pause that stack's top activity.
+ * Pause all activities in either all of the root tasks or just the back root tasks. This is
+ * done before resuming a new activity and to make sure that previously active activities are
+ * paused in root tasks that are no longer visible or in pinned windowing mode. This does not
+ * pause activities in visible root tasks, so if an activity is launched within the same root
+ * task, hen we should explicitly pause that root task's top activity.
*
* @param userLeaving Passed to pauseActivity() to indicate whether to call onUserLeaving().
* @param resuming The resuming activity.
@@ -1217,10 +1408,10 @@
if (resumedActivity != null
&& (task.getVisibility(resuming) != TASK_VISIBILITY_VISIBLE
|| !task.isTopActivityFocusable())) {
- ProtoLog.d(WM_DEBUG_STATES, "pauseBackStacks: task=%s "
+ ProtoLog.d(WM_DEBUG_STATES, "pauseBackTasks: task=%s "
+ "mResumedActivity=%s", task, resumedActivity);
if (task.startPausingLocked(userLeaving, false /* uiSleeping*/,
- resuming, "pauseBackStacks")) {
+ resuming, "pauseBackTasks")) {
someActivityPaused[0]++;
}
}
@@ -1234,18 +1425,21 @@
void findTaskLocked(final ActivityRecord r, final boolean isPreferredDisplayArea,
RootWindowContainer.FindTaskResult result) {
mTmpFindTaskResult.clear();
- for (int stackNdx = mChildren.size() - 1; stackNdx >= 0; --stackNdx) {
- final Task stack = mChildren.get(stackNdx);
- if (!r.hasCompatibleActivityType(stack) && stack.isLeafTask()) {
- ProtoLog.d(WM_DEBUG_TASKS, "Skipping stack: (mismatch activity/stack) "
- + "%s", stack);
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final Task rootTask = mChildren.get(i).asTask();
+ if (rootTask == null) {
+ continue;
+ }
+ if (!r.hasCompatibleActivityType(rootTask) && rootTask.isLeafTask()) {
+ ProtoLog.d(WM_DEBUG_TASKS, "Skipping rootTask: (mismatch activity/rootTask) "
+ + "%s", rootTask);
continue;
}
- mTmpFindTaskResult.process(r, stack);
- // It is possible to have tasks in multiple stacks with the same root affinity, so
+ mTmpFindTaskResult.process(r, rootTask);
+ // It is possible to have tasks in multiple root tasks with the same root affinity, so
// we should keep looking after finding an affinity match to see if there is a
- // better match in another stack. Also, task affinity isn't a good enough reason
+ // better match in another root task. Also, task affinity isn't a good enough reason
// to target a display which isn't the source of the intent, so skip any affinity
// matches not on the specified display.
if (mTmpFindTaskResult.mRecord != null) {
@@ -1253,9 +1447,9 @@
result.setTo(mTmpFindTaskResult);
return;
} else if (isPreferredDisplayArea) {
- // Note: since the traversing through the stacks is top down, the floating
+ // Note: since the traversing through the root tasks is top down, the floating
// tasks should always have lower priority than any affinity-matching tasks
- // in the fullscreen stacks
+ // in the fullscreen root tasks
result.setTo(mTmpFindTaskResult);
}
}
@@ -1474,20 +1668,29 @@
*/
ActivityRecord topRunningActivity(boolean considerKeyguardState) {
ActivityRecord topRunning = null;
- final Task focusedStack = getFocusedRootTask();
- if (focusedStack != null) {
- topRunning = focusedStack.topRunningActivity();
+ final Task focusedRootTask = getFocusedRootTask();
+ if (focusedRootTask != null) {
+ topRunning = focusedRootTask.topRunningActivity();
}
- // Look in other focusable stacks.
+ // Look in other focusable root tasks.
if (topRunning == null) {
for (int i = mChildren.size() - 1; i >= 0; --i) {
- final Task stack = mChildren.get(i);
- // Only consider focusable stacks other than the current focused one.
- if (stack == focusedStack || !stack.isTopActivityFocusable()) {
+ final WindowContainer child = mChildren.get(i);
+ if (child.asTaskDisplayArea() != null) {
+ topRunning =
+ child.asTaskDisplayArea().topRunningActivity(considerKeyguardState);
+ if (topRunning != null) {
+ break;
+ }
continue;
}
- topRunning = stack.topRunningActivity();
+ final Task rootTask = mChildren.get(i).asTask();
+ // Only consider focusable root tasks other than the current focused one.
+ if (rootTask == focusedRootTask || !rootTask.isTopActivityFocusable()) {
+ continue;
+ }
+ topRunning = rootTask.topRunningActivity();
if (topRunning != null) {
break;
}
@@ -1593,35 +1796,44 @@
}
/**
- * Adjusts the {@param stack} behind the last visible stack in the display if necessary.
+ * Adjusts the {@param rootTask} behind the last visible rootTask in the display if necessary.
* Generally used in conjunction with {@link #moveRootTaskBehindRootTask}.
*/
// TODO(b/151575894): Remove special stack movement methods.
void moveRootTaskBehindBottomMostVisibleRootTask(Task rootTask) {
if (rootTask.shouldBeVisible(null)) {
- // Skip if the stack is already visible
+ // Skip if the root task is already visible
return;
}
- // Move the stack to the bottom to not affect the following visibility checks
+ // Move the root task to the bottom to not affect the following visibility checks
rootTask.getParent().positionChildAt(POSITION_BOTTOM, rootTask,
false /* includingParents */);
- // Find the next position where the stack should be placed
+ // Find the next position where the root task should be placed
final boolean isRootTask = rootTask.isRootTask();
final int numRootTasks =
isRootTask ? mChildren.size() : rootTask.getParent().getChildCount();
for (int rootTaskNdx = 0; rootTaskNdx < numRootTasks; rootTaskNdx++) {
- final Task s = isRootTask ? mChildren.get(rootTaskNdx)
- : (Task) rootTask.getParent().getChildAt(rootTaskNdx);
- if (s == rootTask) {
+ Task s;
+ if (isRootTask) {
+ final WindowContainer child = mChildren.get(rootTaskNdx);
+ if (child.asTaskDisplayArea() != null) {
+ s = child.asTaskDisplayArea().getBottomMostVisibleRootTask(rootTask);
+ } else {
+ s = child.asTask();
+ }
+ } else {
+ s = rootTask.getParent().getChildAt(rootTaskNdx).asTask();
+ }
+ if (s == rootTask || s == null) {
continue;
}
final int winMode = s.getWindowingMode();
final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN
|| winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
if (s.shouldBeVisible(null) && isValidWindowingMode) {
- // Move the provided stack to behind this stack
+ // Move the provided root task to behind this root task
final int position = Math.max(0, rootTaskNdx - 1);
rootTask.getParent().positionChildAt(position, rootTask,
false /*includingParents */);
@@ -1630,6 +1842,16 @@
}
}
+ @Nullable
+ private Task getBottomMostVisibleRootTask(Task excludeRootTask) {
+ return getRootTask(task -> {
+ final int winMode = task.getWindowingMode();
+ final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN
+ || winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+ return task.shouldBeVisible(null) && isValidWindowingMode;
+ }, false /* traverseTopToBottom */);
+ }
+
/**
* Moves the {@param stack} behind the given {@param behindStack} if possible. If
* {@param behindStack} is not currently in the display, then then the stack is moved to the
@@ -1735,77 +1957,82 @@
boolean preserveWindows, boolean notifyClients, boolean userLeaving) {
mAtmService.mTaskSupervisor.beginActivityVisibilityUpdate();
try {
- for (int stackNdx = mChildren.size() - 1; stackNdx >= 0; --stackNdx) {
- final Task stack = mChildren.get(stackNdx);
- stack.ensureActivitiesVisible(starting, configChanges, preserveWindows,
+ forAllRootTasks(rootTask -> {
+ rootTask.ensureActivitiesVisible(starting, configChanges, preserveWindows,
notifyClients, userLeaving);
- }
+ });
} finally {
mAtmService.mTaskSupervisor.endActivityVisibilityUpdate();
}
}
/**
- * Removes the stacks in the node applying the content removal node from the display.
+ * Removes the root tasks in the node applying the content removal node from the display.
*
- * @return last reparented stack, or {@code null} if the stacks had to be destroyed.
+ * @return last reparented root task, or {@code null} if the root tasks had to be destroyed.
*/
Task remove() {
mPreferredTopFocusableRootTask = null;
// TODO(b/153090332): Allow setting content removal mode per task display area
final boolean destroyContentOnRemoval = mDisplayContent.shouldDestroyContentOnRemove();
final TaskDisplayArea toDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- Task lastReparentedStack = null;
+ Task lastReparentedRootTask = null;
- // Stacks could be reparented from the removed display area to other display area. After
- // reparenting the last stack of the removed display area, the display area becomes ready to
- // be released (no more ActivityStack-s). But, we cannot release it at that moment or the
- // related WindowContainer will also be removed. So, we set display area as removed after
- // reparenting stack finished.
+ // Root tasks could be reparented from the removed display area to other display area. After
+ // reparenting the last root task of the removed display area, the display area becomes
+ // ready to be released (no more ActivityStack-s). But, we cannot release it at that moment
+ // or the related WindowContainer will also be removed. So, we set display area as removed
+ // after reparenting root task finished.
// Keep the order from bottom to top.
- int numStacks = mChildren.size();
+ int numRootTasks = mChildren.size();
final boolean splitScreenActivated = toDisplayArea.isSplitScreenModeActivated();
- final Task rootStack = splitScreenActivated ? toDisplayArea
+ final Task splitScreenRoot = splitScreenActivated ? toDisplayArea
.getTopRootTaskInWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) : null;
- for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
- final Task stack = mChildren.get(stackNdx);
- // Always finish non-standard type stacks and stacks created by a organizer.
+ for (int i = 0; i < numRootTasks; i++) {
+ final WindowContainer child = mChildren.get(i);
+ if (child.asTaskDisplayArea() != null) {
+ lastReparentedRootTask = child.asTaskDisplayArea().remove();
+ continue;
+ }
+ final Task task = mChildren.get(i).asTask();
+ // Always finish non-standard type root tasks and root tasks created by a organizer.
// TODO: For stacks created by organizer, consider reparenting children tasks if the use
// case arises in the future.
if (destroyContentOnRemoval
- || !stack.isActivityTypeStandardOrUndefined()
- || stack.mCreatedByOrganizer) {
- stack.finishAllActivitiesImmediately();
+ || !task.isActivityTypeStandardOrUndefined()
+ || task.mCreatedByOrganizer) {
+ task.finishAllActivitiesImmediately();
} else {
- // Reparent the stack to the root task of secondary-split-screen or display area.
- stack.reparent(stack.supportsSplitScreenWindowingMode() && rootStack != null
- ? rootStack : toDisplayArea, POSITION_TOP);
+ // Reparent the root task to the root task of secondary-split-screen or display
+ // area.
+ task.reparent(task.supportsSplitScreenWindowingMode() && splitScreenRoot != null
+ ? splitScreenRoot : toDisplayArea, POSITION_TOP);
- // Set the windowing mode to undefined by default to let the stack inherited the
+ // Set the windowing mode to undefined by default to let the root task inherited the
// windowing mode.
- stack.setWindowingMode(WINDOWING_MODE_UNDEFINED);
- lastReparentedStack = stack;
+ task.setWindowingMode(WINDOWING_MODE_UNDEFINED);
+ lastReparentedRootTask = task;
}
- // Stacks may be removed from this display. Ensure each stack will be processed
+ // Root task may be removed from this display. Ensure each root task will be processed
// and the loop will end.
- stackNdx -= numStacks - mChildren.size();
- numStacks = mChildren.size();
+ i -= numRootTasks - mChildren.size();
+ numRootTasks = mChildren.size();
}
- if (lastReparentedStack != null && splitScreenActivated) {
- if (!lastReparentedStack.supportsSplitScreenWindowingMode()) {
+ if (lastReparentedRootTask != null && splitScreenActivated) {
+ if (!lastReparentedRootTask.supportsSplitScreenWindowingMode()) {
mAtmService.getTaskChangeNotificationController()
.notifyActivityDismissingDockedStack();
- toDisplayArea.onSplitScreenModeDismissed(lastReparentedStack);
- } else if (rootStack != null) {
+ toDisplayArea.onSplitScreenModeDismissed(lastReparentedRootTask);
+ } else if (splitScreenRoot != null) {
// update focus
- rootStack.moveToFront("display-removed");
+ splitScreenRoot.moveToFront("display-removed");
}
}
mRemoved = true;
- return lastReparentedStack;
+ return lastReparentedRootTask;
}
/** Whether this task display area can request orientation. */
@@ -1842,8 +2069,13 @@
}
final String triplePrefix = doublePrefix + " ";
pw.println(doublePrefix + "Application tokens in top down Z order:");
- for (int rootTaskNdx = getChildCount() - 1; rootTaskNdx >= 0; --rootTaskNdx) {
- final Task rootTask = getChildAt(rootTaskNdx);
+ for (int index = getChildCount() - 1; index >= 0; --index) {
+ final WindowContainer child = getChildAt(index);
+ if (child.asTaskDisplayArea() != null) {
+ child.dump(pw, doublePrefix, dumpAll);
+ continue;
+ }
+ final Task rootTask = child.asTask();
pw.println(doublePrefix + "* " + rootTask);
rootTask.dump(pw, triplePrefix, dumpAll);
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 9f8c35b..929d7bf 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -39,6 +39,7 @@
import android.view.SurfaceControl;
import android.window.ITaskOrganizer;
import android.window.ITaskOrganizerController;
+import android.window.StartingWindowInfo;
import android.window.TaskAppearedInfo;
import android.window.WindowContainerToken;
@@ -116,10 +117,10 @@
}
void addStartingWindow(Task task, IBinder appToken) {
- final RunningTaskInfo taskInfo = task.getTaskInfo();
+ final StartingWindowInfo info = task.getStartingWindowInfo();
mDeferTaskOrgCallbacksConsumer.accept(() -> {
try {
- mTaskOrganizer.addStartingWindow(taskInfo, appToken);
+ mTaskOrganizer.addStartingWindow(info, appToken);
} catch (RemoteException e) {
Slog.e(TAG, "Exception sending onTaskStart callback", e);
}
@@ -127,10 +128,9 @@
}
void removeStartingWindow(Task task) {
- final RunningTaskInfo taskInfo = task.getTaskInfo();
mDeferTaskOrgCallbacksConsumer.accept(() -> {
try {
- mTaskOrganizer.removeStartingWindow(taskInfo);
+ mTaskOrganizer.removeStartingWindow(task.mTaskId);
} catch (RemoteException e) {
Slog.e(TAG, "Exception sending onStartTaskFinished callback", e);
}
@@ -152,23 +152,27 @@
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task appeared taskId=%d", task.mTaskId);
final boolean visible = task.isVisible();
final RunningTaskInfo taskInfo = task.getTaskInfo();
- try {
- mTaskOrganizer.onTaskAppeared(taskInfo, prepareLeash(task, visible,
- "TaskOrganizerController.onTaskAppeared"));
- } catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onTaskAppeared callback", e);
- }
+ mDeferTaskOrgCallbacksConsumer.accept(() -> {
+ try {
+ mTaskOrganizer.onTaskAppeared(taskInfo, prepareLeash(task, visible,
+ "TaskOrganizerController.onTaskAppeared"));
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception sending onTaskAppeared callback", e);
+ }
+ });
}
void onTaskVanished(Task task) {
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task vanished taskId=%d", task.mTaskId);
final RunningTaskInfo taskInfo = task.getTaskInfo();
- try {
- mTaskOrganizer.onTaskVanished(taskInfo);
- } catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onTaskVanished callback", e);
- }
+ mDeferTaskOrgCallbacksConsumer.accept(() -> {
+ try {
+ mTaskOrganizer.onTaskVanished(taskInfo);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception sending onTaskVanished callback", e);
+ }
+ });
}
void onTaskInfoChanged(Task task, ActivityManager.RunningTaskInfo taskInfo) {
@@ -177,18 +181,20 @@
return;
}
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task info changed taskId=%d", task.mTaskId);
- if (!task.isOrganized()) {
- // This is safe to ignore if the task is no longer organized
- return;
- }
- try {
- // Purposely notify of task info change immediately instead of deferring (like
- // appear and vanish) to allow info changes (such as new PIP params) to flow
- // without waiting.
- mTaskOrganizer.onTaskInfoChanged(taskInfo);
- } catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onTaskInfoChanged callback", e);
- }
+ mDeferTaskOrgCallbacksConsumer.accept(() -> {
+ if (!task.isOrganized()) {
+ // This is safe to ignore if the task is no longer organized
+ return;
+ }
+ try {
+ // Purposely notify of task info change immediately instead of deferring (like
+ // appear and vanish) to allow info changes (such as new PIP params) to flow
+ // without waiting.
+ mTaskOrganizer.onTaskInfoChanged(taskInfo);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception sending onTaskInfoChanged callback", e);
+ }
+ });
}
void onBackPressedOnTaskRoot(Task task) {
@@ -198,15 +204,17 @@
// Skip if the task has not yet received taskAppeared().
return;
}
- if (!task.isOrganized()) {
- // This is safe to ignore if the task is no longer organized
- return;
- }
- try {
- mTaskOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo());
- } catch (Exception e) {
- Slog.e(TAG, "Exception sending onBackPressedOnTaskRoot callback", e);
- }
+ mDeferTaskOrgCallbacksConsumer.accept(() -> {
+ if (!task.isOrganized()) {
+ // This is safe to ignore if the task is no longer organized
+ return;
+ }
+ try {
+ mTaskOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo());
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception sending onBackPressedOnTaskRoot callback", e);
+ }
+ });
}
}
@@ -251,34 +259,28 @@
return mOrganizer.prepareLeash(t, t.isVisible(), reason);
}
- private boolean addTask(Task t) {
- if (t.mTaskAppearedSent) {
- return false;
- }
+ void addTask(Task t) {
+ if (t.mTaskAppearedSent) return;
if (!mOrganizedTasks.contains(t)) {
mOrganizedTasks.add(t);
}
-
if (t.taskAppearedReady()) {
t.mTaskAppearedSent = true;
- return true;
+ mOrganizer.onTaskAppeared(t);
}
- return false;
}
- private boolean removeTask(Task t) {
- mOrganizedTasks.remove(t);
- mInterceptBackPressedOnRootTasks.remove(t.mTaskId);
-
+ void removeTask(Task t) {
if (t.mTaskAppearedSent) {
if (t.getSurfaceControl() != null) {
t.migrateToNewSurfaceControl();
}
t.mTaskAppearedSent = false;
- return true;
+ mOrganizer.onTaskVanished(t);
}
- return false;
+ mOrganizedTasks.remove(t);
+ mInterceptBackPressedOnRootTasks.remove(t.mTaskId);
}
void dispose() {
@@ -290,7 +292,7 @@
while (!mOrganizedTasks.isEmpty()) {
final Task t = mOrganizedTasks.get(0);
if (!t.updateTaskOrganizerState(true /* forceUpdate */)) {
- TaskOrganizerController.this.onTaskVanished(mOrganizer.mTaskOrganizer, t);
+ removeTask(t);
}
}
@@ -304,33 +306,6 @@
}
}
- static class PendingTaskEvent {
- static final int EVENT_APPEARED = 0;
- static final int EVENT_VANISHED = 1;
- static final int EVENT_INFO_CHANGED = 2;
- static final int EVENT_ROOT_BACK_PRESSED = 3;
-
- final int mEventType;
- final Task mTask;
- final ITaskOrganizer mTaskOrg;
- boolean mForce;
-
- PendingTaskEvent(Task task, int event) {
- this(task, task.mTaskOrganizer, event);
- }
-
- PendingTaskEvent(Task task, ITaskOrganizer taskOrg, int eventType) {
- mTask = task;
- mTaskOrg = taskOrg;
- mEventType = eventType;
- }
-
- boolean isLifecycleEvent() {
- return mEventType == EVENT_APPEARED || mEventType == EVENT_VANISHED
- || mEventType == EVENT_INFO_CHANGED;
- }
- }
-
private final ActivityTaskManagerService mService;
private final WindowManagerGlobalLock mGlobalLock;
@@ -338,8 +313,7 @@
private final LinkedList<ITaskOrganizer> mTaskOrganizers = new LinkedList<>();
private final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap<>();
private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
- // Pending task events due to layout deferred.
- private final ArrayList<PendingTaskEvent> mPendingTaskEvents = new ArrayList<>();
+ private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>();
// Set of organized tasks (by taskId) that dispatch back pressed to their organizers
private final HashSet<Integer> mInterceptBackPressedOnRootTasks = new HashSet();
@@ -364,12 +338,6 @@
public void setDeferTaskOrgCallbacksConsumer(Consumer<Runnable> consumer) {
mDeferTaskOrgCallbacksConsumer = consumer;
}
-
- @VisibleForTesting
- ArrayList<PendingTaskEvent> getPendingEventList() {
- return mPendingTaskEvents;
- }
-
/**
* Register a TaskOrganizer to manage tasks as they enter the a supported windowing mode.
*/
@@ -475,33 +443,13 @@
void onTaskAppeared(ITaskOrganizer organizer, Task task) {
final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
- if (state != null && state.addTask(task)) {
- PendingTaskEvent pending = getPendingTaskEvent(task, PendingTaskEvent.EVENT_APPEARED);
- if (pending == null) {
- pending = new PendingTaskEvent(task, PendingTaskEvent.EVENT_APPEARED);
- mPendingTaskEvents.add(pending);
- }
- }
+ state.addTask(task);
}
void onTaskVanished(ITaskOrganizer organizer, Task task) {
final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
- if (state != null && state.removeTask(task)) {
- for (int i = mPendingTaskEvents.size() - 1; i >= 0; i--) {
- PendingTaskEvent entry = mPendingTaskEvents.get(i);
- if (task.mTaskId == entry.mTask.mTaskId) {
- // This task will vanished so remove all pending event of it.
- mPendingTaskEvents.remove(i);
- if (entry.mEventType == PendingTaskEvent.EVENT_APPEARED) {
- // If task still not appeared, ignore this callback.
- return;
- }
- }
- }
-
- PendingTaskEvent pending =
- new PendingTaskEvent(task, organizer, PendingTaskEvent.EVENT_VANISHED);
- mPendingTaskEvents.add(pending);
+ if (state != null) {
+ state.removeTask(task);
}
}
@@ -566,76 +514,30 @@
}
}
- void dispatchPendingEvents() {
- if (mService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()
- || mPendingTaskEvents.isEmpty()) {
+ void dispatchPendingTaskInfoChanges() {
+ if (mService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()) {
return;
}
-
- for (int i = 0, n = mPendingTaskEvents.size(); i < n; i++) {
- PendingTaskEvent event = mPendingTaskEvents.get(i);
- final Task task = event.mTask;
- final TaskOrganizerState state;
- switch (event.mEventType) {
- case PendingTaskEvent.EVENT_APPEARED:
- state = mTaskOrganizerStates.get(event.mTaskOrg.asBinder());
- if (state != null && task.taskAppearedReady()) {
- state.mOrganizer.onTaskAppeared(task);
- }
- break;
- case PendingTaskEvent.EVENT_VANISHED:
- state = mTaskOrganizerStates.get(event.mTaskOrg.asBinder());
- if (state != null) {
- state.mOrganizer.onTaskVanished(task);
- }
- break;
- case PendingTaskEvent.EVENT_INFO_CHANGED:
- dispatchTaskInfoChanged(event.mTask, event.mForce);
- break;
- case PendingTaskEvent.EVENT_ROOT_BACK_PRESSED:
- state = mTaskOrganizerStates.get(event.mTaskOrg.asBinder());
- if (state != null) {
- state.mOrganizer.onBackPressedOnTaskRoot(task);
- }
- break;
- }
+ for (int i = 0, n = mPendingTaskInfoChanges.size(); i < n; ++i) {
+ dispatchTaskInfoChanged(mPendingTaskInfoChanges.get(i), false /* force */);
}
- mPendingTaskEvents.clear();
+ mPendingTaskInfoChanges.clear();
}
- void onTaskInfoChanged(Task task, boolean force) {
- if (!task.mTaskAppearedSent) {
- // Skip if task still not appeared.
+ void dispatchTaskInfoChanged(Task task, boolean force) {
+ if (!force && mService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()) {
+ // Defer task info reporting while layout is deferred. This is because layout defer
+ // blocks tend to do lots of re-ordering which can mess up animations in receivers.
+ mPendingTaskInfoChanges.remove(task);
+ mPendingTaskInfoChanges.add(task);
return;
}
-
- // Defer task info reporting while layout is deferred. This is because layout defer
- // blocks tend to do lots of re-ordering which can mess up animations in receivers.
- PendingTaskEvent pending = getPendingLifecycleTaskEvent(task);
- if (pending == null) {
- pending = new PendingTaskEvent(task, PendingTaskEvent.EVENT_INFO_CHANGED);
- } else {
- if (pending.mEventType != PendingTaskEvent.EVENT_INFO_CHANGED) {
- // If queued event is appeared, it means task still not appeared so ignore
- // this info changed. If queued event is vanished, it means task should
- // will vanished early so do not need this info changed.
- return;
- }
- // Remove and add for re-ordering.
- mPendingTaskEvents.remove(pending);
- }
- pending.mForce = force;
- mPendingTaskEvents.add(pending);
- }
-
- private void dispatchTaskInfoChanged(Task task, boolean force) {
RunningTaskInfo lastInfo = mLastSentTaskInfos.get(task);
if (mTmpTaskInfo == null) {
mTmpTaskInfo = new RunningTaskInfo();
}
mTmpTaskInfo.configuration.unset();
task.fillTaskInfo(mTmpTaskInfo);
-
boolean changed = !mTmpTaskInfo.equalsForTaskOrganizer(lastInfo);
if (!changed) {
int cfgChanges = mTmpTaskInfo.configuration.diff(lastInfo.configuration);
@@ -837,48 +739,11 @@
return false;
}
- PendingTaskEvent pendingVanished =
- getPendingTaskEvent(task, PendingTaskEvent.EVENT_VANISHED);
- if (pendingVanished != null) {
- // This task will vanish before this callback so just ignore.
- return false;
- }
-
- PendingTaskEvent pending = getPendingTaskEvent(
- task, PendingTaskEvent.EVENT_ROOT_BACK_PRESSED);
- if (pending == null) {
- pending = new PendingTaskEvent(task, PendingTaskEvent.EVENT_ROOT_BACK_PRESSED);
- } else {
- // Pending already exist, remove and add for re-ordering.
- mPendingTaskEvents.remove(pending);
- }
- mPendingTaskEvents.add(pending);
+ final TaskOrganizerState state = mTaskOrganizerStates.get(task.mTaskOrganizer.asBinder());
+ state.mOrganizer.onBackPressedOnTaskRoot(task);
return true;
}
- @Nullable
- private PendingTaskEvent getPendingTaskEvent(Task task, int type) {
- for (int i = mPendingTaskEvents.size() - 1; i >= 0; i--) {
- PendingTaskEvent entry = mPendingTaskEvents.get(i);
- if (task.mTaskId == entry.mTask.mTaskId && type == entry.mEventType) {
- return entry;
- }
- }
- return null;
- }
-
- @VisibleForTesting
- @Nullable
- PendingTaskEvent getPendingLifecycleTaskEvent(Task task) {
- for (int i = mPendingTaskEvents.size() - 1; i >= 0; i--) {
- PendingTaskEvent entry = mPendingTaskEvents.get(i);
- if (task.mTaskId == entry.mTask.mTaskId && entry.isLifecycleEvent()) {
- return entry;
- }
- }
- return null;
- }
-
public void dump(PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.print(prefix); pw.println("TaskOrganizerController:");
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index d5e4dac..8c458a2 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -49,7 +49,6 @@
import android.annotation.Nullable;
import android.app.ActivityManager.TaskDescription;
-import android.window.TaskSnapshot;
import android.app.ActivityThread;
import android.content.Context;
import android.graphics.Canvas;
@@ -78,6 +77,7 @@
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.window.ClientWindowFrames;
+import android.window.TaskSnapshot;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -100,7 +100,7 @@
* with a window with the exact same dimensions etc. However, these flags are not used in layout
* and might cause other side effects so we exclude them.
*/
- private static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE
+ static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE
| FLAG_NOT_TOUCHABLE
| FLAG_NOT_TOUCH_MODAL
| FLAG_ALT_FOCUSABLE_IM
@@ -180,34 +180,10 @@
synchronized (service.mGlobalLock) {
final WindowState mainWindow = activity.findMainWindow();
final Task task = activity.getTask();
- if (task == null) {
- Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find task for activity="
- + activity);
- return null;
- }
final ActivityRecord topFullscreenActivity =
activity.getTask().getTopFullscreenActivity();
- if (topFullscreenActivity == null) {
- Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find top fullscreen for task="
- + task);
- return null;
- }
+ // Already check the nullity in StartingSurfaceController#createTaskSnapshotSurface
topFullscreenOpaqueWindow = topFullscreenActivity.getTopFullscreenOpaqueWindow();
- if (mainWindow == null || topFullscreenOpaqueWindow == null) {
- Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for activity="
- + activity);
- return null;
- }
- if (topFullscreenActivity.getWindowConfiguration().getRotation()
- != snapshot.getRotation()) {
- // The snapshot should have been checked by ActivityRecord#isSnapshotCompatible
- // that the activity will be updated to the same rotation as the snapshot. Since
- // the transition is not started yet, fixed rotation transform needs to be applied
- // earlier to make the snapshot show in a rotated container.
- activity.mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(
- topFullscreenActivity, false /* checkOpening */);
- }
-
WindowManager.LayoutParams attrs = topFullscreenOpaqueWindow.mAttrs;
appearance = attrs.insetsFlags.appearance;
windowFlags = attrs.flags;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index d310260..1805ddd 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2624,16 +2624,24 @@
// events can slip to activity from letterbox.
mActivityRecord.getLetterboxInnerBounds(mTmpRect);
if (mTmpRect.isEmpty()) {
- // If this is a modal window we need to dismiss it if it's not full screen
- // and the touch happens outside of the frame that displays the content. This
- // means we need to intercept touches outside of that window. The dim layer
- // user associated with the window (task or stack) will give us the good
- // bounds, as they would be used to display the dim layer.
- final Task task = getTask();
- if (task != null) {
- task.getDimBounds(mTmpRect);
- } else if (getRootTask() != null) {
- getRootTask().getDimBounds(mTmpRect);
+ final Rect transformedBounds = mActivityRecord.getFixedRotationTransformDisplayBounds();
+ if (transformedBounds != null) {
+ // Task is in the same orientation as display, so the rotated bounds should be
+ // chosen as the touchable region. Then when the surface layer transforms the
+ // region to display space, the orientation will be consistent.
+ mTmpRect.set(transformedBounds);
+ } else {
+ // If this is a modal window we need to dismiss it if it's not full screen
+ // and the touch happens outside of the frame that displays the content. This
+ // means we need to intercept touches outside of that window. The dim layer
+ // user associated with the window (task or stack) will give us the good
+ // bounds, as they would be used to display the dim layer.
+ final Task task = getTask();
+ if (task != null) {
+ task.getDimBounds(mTmpRect);
+ } else if (getRootTask() != null) {
+ getRootTask().getDimBounds(mTmpRect);
+ }
}
}
adjustRegionInFreefromWindowMode(mTmpRect);
@@ -5229,14 +5237,17 @@
if (!mAnimatingExit && mAppDied) {
mIsDimming = true;
getDimmer().dimAbove(getSyncTransaction(), this, DEFAULT_DIM_AMOUNT_DEAD_WINDOW);
- } else if ((mAttrs.flags & FLAG_DIM_BEHIND) != 0 && isVisibleNow() && !mHidden) {
- // Only show a dim behind when the following is satisfied:
- // 1. The window has the flag FLAG_DIM_BEHIND
+ } else if (((mAttrs.flags & FLAG_DIM_BEHIND) != 0 || mAttrs.backgroundBlurRadius != 0)
+ && isVisibleNow() && !mHidden) {
+ // Only show the Dimmer when the following is satisfied:
+ // 1. The window has the flag FLAG_DIM_BEHIND or background blur is requested
// 2. The WindowToken is not hidden so dims aren't shown when the window is exiting.
// 3. The WS is considered visible according to the isVisible() method
// 4. The WS is not hidden.
mIsDimming = true;
- getDimmer().dimBelow(getSyncTransaction(), this, mAttrs.dimAmount);
+ final float dimAmount = (mAttrs.flags & FLAG_DIM_BEHIND) != 0 ? mAttrs.dimAmount : 0;
+ getDimmer().dimBelow(
+ getSyncTransaction(), this, mAttrs.dimAmount, mAttrs.backgroundBlurRadius);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index badfe96..585db1e 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -802,7 +802,6 @@
if (displayed) {
w.mToken.hasVisible = true;
- mSurfaceController.setBackgroundBlurRadius(w.mAttrs.backgroundBlurRadius);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 788f004..f59eba9 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -64,8 +64,6 @@
private float mLastDsdy = 0;
private float mLastDtdy = 1;
- private int mLastBackgroundBlurRadius = 0;
-
private float mSurfaceAlpha = 0;
private int mSurfaceLayer = 0;
@@ -242,26 +240,6 @@
}
}
- void setBackgroundBlurRadius(int radius) {
- ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE backgroundBlur=%o: %s", radius, title);
-
- if (mSurfaceControl == null || radius == mLastBackgroundBlurRadius) {
- return;
- }
- mLastBackgroundBlurRadius = radius;
-
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setBackgroundBlurRadius");
- mService.openSurfaceTransaction();
- try {
- getGlobalTransaction().setBackgroundBlurRadius(mSurfaceControl, radius);
- } finally {
- mService.closeSurfaceTransaction("setBackgroundBlurRadius");
- if (SHOW_LIGHT_TRANSACTIONS) {
- Slog.i(TAG, "<<< CLOSE TRANSACTION setBackgroundBlurRadius");
- }
- }
- }
-
void setSecure(boolean isSecure) {
ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE isSecure=%b: %s", isSecure, title);
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 2c4eb1b..77ca4e9 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -40,6 +40,7 @@
"com_android_server_locksettings_SyntheticPasswordManager.cpp",
"com_android_server_net_NetworkStatsService.cpp",
"com_android_server_power_PowerManagerService.cpp",
+ "com_android_server_powerstats_PowerStatsService.cpp",
"com_android_server_security_VerityUtils.cpp",
"com_android_server_SerialService.cpp",
"com_android_server_soundtrigger_middleware_AudioSessionProviderImpl.cpp",
diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS
index 7fc5565..995cfe9 100644
--- a/services/core/jni/OWNERS
+++ b/services/core/jni/OWNERS
@@ -23,6 +23,7 @@
per-file com_android_server_net_* = file:/services/core/java/com/android/server/net/OWNERS
per-file com_android_server_pm_* = file:/services/core/java/com/android/server/pm/OWNERS
per-file com_android_server_power_* = file:/services/core/java/com/android/server/power/OWNERS
+per-file com_android_server_powerstats_* = file:/services/core/java/com/android/server/powerstats/OWNERS
per-file com_android_server_se_* = file:/core/java/android/se/OWNERS
per-file com_android_server_security_* = file:/core/java/android/security/OWNERS
per-file com_android_server_tv_* = file:/media/java/android/media/tv/OWNERS
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 27634bf..57d28ba 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -62,11 +62,11 @@
#include <nativehelper/ScopedPrimitiveArray.h>
#include <nativehelper/ScopedUtfChars.h>
-#include "com_android_server_power_PowerManagerService.h"
+#include "android_hardware_display_DisplayViewport.h"
#include "android_hardware_input_InputApplicationHandle.h"
#include "android_hardware_input_InputWindowHandle.h"
-#include "android_hardware_display_DisplayViewport.h"
#include "android_util_Binder.h"
+#include "com_android_server_power_PowerManagerService.h"
#include <vector>
@@ -101,6 +101,8 @@
jmethodID notifyConnectionUnresponsive;
jmethodID notifyConnectionResponsive;
jmethodID notifyFocusChanged;
+ jmethodID notifySensorEvent;
+ jmethodID notifySensorAccuracy;
jmethodID notifyUntrustedTouch;
jmethodID filterInputEvent;
jmethodID interceptKeyBeforeQueueing;
@@ -157,6 +159,29 @@
jmethodID size;
} gSparseArrayClassInfo;
+struct InputSensorInfoOffsets {
+ jclass clazz;
+ // fields
+ jfieldID name;
+ jfieldID vendor;
+ jfieldID version;
+ jfieldID handle;
+ jfieldID maxRange;
+ jfieldID resolution;
+ jfieldID power;
+ jfieldID minDelay;
+ jfieldID fifoReservedEventCount;
+ jfieldID fifoMaxEventCount;
+ jfieldID stringType;
+ jfieldID requiredPermission;
+ jfieldID maxDelay;
+ jfieldID flags;
+ jfieldID type;
+ jfieldID id;
+ // methods
+ jmethodID init;
+} gInputSensorInfo;
+
// --- Global functions ---
template<typename T>
@@ -224,7 +249,8 @@
const std::string& name);
base::Result<std::unique_ptr<InputChannel>> createInputMonitor(JNIEnv* env, int32_t displayId,
bool isGestureMonitor,
- const std::string& name);
+ const std::string& name,
+ int32_t pid);
status_t removeInputChannel(JNIEnv* env, const sp<IBinder>& connectionToken);
status_t pilferPointers(const sp<IBinder>& token);
@@ -267,6 +293,11 @@
void notifyConnectionResponsive(const sp<IBinder>& token) override;
void notifyInputChannelBroken(const sp<IBinder>& token) override;
void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) override;
+ void notifySensorEvent(int32_t deviceId, InputDeviceSensorType sensorType,
+ InputDeviceSensorAccuracy accuracy, nsecs_t timestamp,
+ const std::vector<float>& values) override;
+ void notifySensorAccuracy(int32_t deviceId, InputDeviceSensorType sensorType,
+ InputDeviceSensorAccuracy accuracy) override;
void notifyUntrustedTouch(const std::string& obscuringPackage) override;
bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) override;
void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override;
@@ -457,9 +488,11 @@
}
base::Result<std::unique_ptr<InputChannel>> NativeInputManager::createInputMonitor(
- JNIEnv* /* env */, int32_t displayId, bool isGestureMonitor, const std::string& name) {
+ JNIEnv* /* env */, int32_t displayId, bool isGestureMonitor, const std::string& name,
+ int32_t pid) {
ATRACE_CALL();
- return mInputManager->getDispatcher()->createInputMonitor(displayId, isGestureMonitor, name);
+ return mInputManager->getDispatcher()->createInputMonitor(displayId, isGestureMonitor, name,
+ pid);
}
status_t NativeInputManager::removeInputChannel(JNIEnv* /* env */,
@@ -820,6 +853,35 @@
checkAndClearExceptionFromCallback(env, "notifyFocusChanged");
}
+void NativeInputManager::notifySensorEvent(int32_t deviceId, InputDeviceSensorType sensorType,
+ InputDeviceSensorAccuracy accuracy, nsecs_t timestamp,
+ const std::vector<float>& values) {
+#if DEBUG_INPUT_DISPATCHER_POLICY
+ ALOGD("notifySensorEvent");
+#endif
+ ATRACE_CALL();
+ JNIEnv* env = jniEnv();
+ ScopedLocalFrame localFrame(env);
+ jfloatArray arr = env->NewFloatArray(values.size());
+ env->SetFloatArrayRegion(arr, 0, values.size(), values.data());
+ env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifySensorEvent, deviceId,
+ static_cast<jint>(sensorType), accuracy, timestamp, arr);
+ checkAndClearExceptionFromCallback(env, "notifySensorEvent");
+}
+
+void NativeInputManager::notifySensorAccuracy(int32_t deviceId, InputDeviceSensorType sensorType,
+ InputDeviceSensorAccuracy accuracy) {
+#if DEBUG_INPUT_DISPATCHER_POLICY
+ ALOGD("notifySensorAccuracy");
+#endif
+ ATRACE_CALL();
+ JNIEnv* env = jniEnv();
+ ScopedLocalFrame localFrame(env);
+ env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifySensorAccuracy, deviceId,
+ static_cast<jint>(sensorType), accuracy);
+ checkAndClearExceptionFromCallback(env, "notifySensorAccuracy");
+}
+
void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
ATRACE_CALL();
JNIEnv* env = jniEnv();
@@ -1444,7 +1506,7 @@
}
static jobject nativeCreateInputMonitor(JNIEnv* env, jclass /* clazz */, jlong ptr, jint displayId,
- jboolean isGestureMonitor, jstring nameObj) {
+ jboolean isGestureMonitor, jstring nameObj, jint pid) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
if (displayId == ADISPLAY_ID_NONE) {
@@ -1457,7 +1519,7 @@
std::string name = nameChars.c_str();
base::Result<std::unique_ptr<InputChannel>> inputChannel =
- im->createInputMonitor(env, displayId, isGestureMonitor, name);
+ im->createInputMonitor(env, displayId, isGestureMonitor, name, pid);
if (!inputChannel) {
std::string message = inputChannel.error().message();
@@ -1911,6 +1973,111 @@
im->setMotionClassifierEnabled(enabled);
}
+static jobject createInputSensorInfo(JNIEnv* env, jstring name, jstring vendor, jint version,
+ jint handle, jint type, jfloat maxRange, jfloat resolution,
+ jfloat power, jfloat minDelay, jint fifoReservedEventCount,
+ jint fifoMaxEventCount, jstring stringType,
+ jstring requiredPermission, jint maxDelay, jint flags,
+ jint id) {
+ // SensorInfo sensorInfo = new Sensor();
+ jobject sensorInfo = env->NewObject(gInputSensorInfo.clazz, gInputSensorInfo.init, "");
+
+ if (sensorInfo != NULL) {
+ env->SetObjectField(sensorInfo, gInputSensorInfo.name, name);
+ env->SetObjectField(sensorInfo, gInputSensorInfo.vendor, vendor);
+ env->SetIntField(sensorInfo, gInputSensorInfo.version, version);
+ env->SetIntField(sensorInfo, gInputSensorInfo.handle, handle);
+ env->SetFloatField(sensorInfo, gInputSensorInfo.maxRange, maxRange);
+ env->SetFloatField(sensorInfo, gInputSensorInfo.resolution, resolution);
+ env->SetFloatField(sensorInfo, gInputSensorInfo.power, power);
+ env->SetIntField(sensorInfo, gInputSensorInfo.minDelay, minDelay);
+ env->SetIntField(sensorInfo, gInputSensorInfo.fifoReservedEventCount,
+ fifoReservedEventCount);
+ env->SetIntField(sensorInfo, gInputSensorInfo.fifoMaxEventCount, fifoMaxEventCount);
+ env->SetObjectField(sensorInfo, gInputSensorInfo.requiredPermission, requiredPermission);
+ env->SetIntField(sensorInfo, gInputSensorInfo.maxDelay, maxDelay);
+ env->SetIntField(sensorInfo, gInputSensorInfo.flags, flags);
+ env->SetObjectField(sensorInfo, gInputSensorInfo.stringType, stringType);
+ env->SetIntField(sensorInfo, gInputSensorInfo.type, type);
+ env->SetIntField(sensorInfo, gInputSensorInfo.id, id);
+ }
+ return sensorInfo;
+}
+
+static jobjectArray nativeGetSensorList(JNIEnv* env, jclass /* clazz */, jlong ptr, jint deviceId) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+ std::vector<InputDeviceInfo> devices = im->getInputManager()->getReader()->getInputDevices();
+ // Find the input device by deviceId
+ auto it = std::find_if(devices.begin(), devices.end(),
+ [deviceId](InputDeviceInfo& info) { return info.getId() == deviceId; });
+
+ if (it == devices.end()) {
+ // Return an array of size 0
+ return env->NewObjectArray(0, gInputSensorInfo.clazz, nullptr);
+ }
+
+ std::vector<InputDeviceSensorType> types = it->getSensorTypes();
+ jobjectArray arr = env->NewObjectArray(types.size(), gInputSensorInfo.clazz, nullptr);
+ for (int i = 0; i < types.size(); i++) {
+ const InputDeviceSensorInfo* sensorInfo = it->getSensorInfo(types[i]);
+ if (sensorInfo == nullptr) {
+ ALOGW("Failed to get input device %d sensor info for type %s", deviceId,
+ NamedEnum::string(types[i]).c_str());
+ continue;
+ }
+
+ jobject info =
+ createInputSensorInfo(env, env->NewStringUTF(sensorInfo->name.c_str()),
+ env->NewStringUTF(sensorInfo->vendor.c_str()),
+ (jint)sensorInfo->version, 0 /* handle */,
+ (jint)sensorInfo->type, (jfloat)sensorInfo->maxRange,
+ (jfloat)sensorInfo->resolution, (jfloat)sensorInfo->power,
+ (jfloat)sensorInfo->minDelay,
+ (jint)sensorInfo->fifoReservedEventCount,
+ (jint)sensorInfo->fifoMaxEventCount,
+ env->NewStringUTF(sensorInfo->stringType.c_str()),
+ env->NewStringUTF("") /* requiredPermission */,
+ (jint)sensorInfo->maxDelay, (jint)sensorInfo->flags,
+ (jint)sensorInfo->id);
+ env->SetObjectArrayElement(arr, i, info);
+ env->DeleteLocalRef(info);
+ }
+ return arr;
+}
+
+static jboolean nativeEnableSensor(JNIEnv* env, jclass /* clazz */, jlong ptr, jint deviceId,
+ jint sensorType, jint samplingPeriodUs,
+ jint maxBatchReportLatencyUs) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ return im->getInputManager()
+ ->getReader()
+ ->enableSensor(deviceId, static_cast<InputDeviceSensorType>(sensorType),
+ std::chrono::microseconds(samplingPeriodUs),
+ std::chrono::microseconds(maxBatchReportLatencyUs));
+ return true;
+}
+
+static void nativeDisableSensor(JNIEnv* env, jclass /* clazz */, jlong ptr, jint deviceId,
+ jint sensorType) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ im->getInputManager()->getReader()->disableSensor(deviceId,
+ static_cast<InputDeviceSensorType>(
+ sensorType));
+}
+
+static jboolean nativeFlushSensor(JNIEnv* env, jclass /* clazz */, jlong ptr, jint deviceId,
+ jint sensorType) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ im->getInputManager()->getReader()->flushSensor(deviceId,
+ static_cast<InputDeviceSensorType>(sensorType));
+ return im->getInputManager()->getDispatcher()->flushSensor(deviceId,
+ static_cast<InputDeviceSensorType>(
+ sensorType));
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gInputManagerMethods[] = {
@@ -1928,7 +2095,7 @@
{"nativeHasKeys", "(JII[I[Z)Z", (void*)nativeHasKeys},
{"nativeCreateInputChannel", "(JLjava/lang/String;)Landroid/view/InputChannel;",
(void*)nativeCreateInputChannel},
- {"nativeCreateInputMonitor", "(JIZLjava/lang/String;)Landroid/view/InputChannel;",
+ {"nativeCreateInputMonitor", "(JIZLjava/lang/String;I)Landroid/view/InputChannel;",
(void*)nativeCreateInputMonitor},
{"nativeRemoveInputChannel", "(JLandroid/os/IBinder;)V", (void*)nativeRemoveInputChannel},
{"nativePilferPointers", "(JLandroid/os/IBinder;)V", (void*)nativePilferPointers},
@@ -1976,6 +2143,11 @@
{"nativeCanDispatchToDisplay", "(JII)Z", (void*)nativeCanDispatchToDisplay},
{"nativeNotifyPortAssociationsChanged", "(J)V", (void*)nativeNotifyPortAssociationsChanged},
{"nativeSetMotionClassifierEnabled", "(JZ)V", (void*)nativeSetMotionClassifierEnabled},
+ {"nativeGetSensorList", "(JI)[Landroid/hardware/input/InputSensorInfo;",
+ (void*)nativeGetSensorList},
+ {"nativeEnableSensor", "(JIIII)Z", (void*)nativeEnableSensor},
+ {"nativeDisableSensor", "(JII)V", (void*)nativeDisableSensor},
+ {"nativeFlushSensor", "(JII)Z", (void*)nativeFlushSensor},
};
#define FIND_CLASS(var, className) \
@@ -2021,6 +2193,10 @@
GET_METHOD_ID(gServiceClassInfo.notifyFocusChanged, clazz,
"notifyFocusChanged", "(Landroid/os/IBinder;Landroid/os/IBinder;)V");
+ GET_METHOD_ID(gServiceClassInfo.notifySensorEvent, clazz, "notifySensorEvent", "(IIIJ[F)V");
+
+ GET_METHOD_ID(gServiceClassInfo.notifySensorAccuracy, clazz, "notifySensorAccuracy", "(III)V");
+
GET_METHOD_ID(gServiceClassInfo.notifyUntrustedTouch, clazz, "notifyUntrustedTouch",
"(Ljava/lang/String;)V");
@@ -2145,6 +2321,33 @@
GET_METHOD_ID(gSparseArrayClassInfo.valueAt, gSparseArrayClassInfo.clazz, "valueAt",
"(I)Ljava/lang/Object;");
GET_METHOD_ID(gSparseArrayClassInfo.size, gSparseArrayClassInfo.clazz, "size", "()I");
+ // InputSensorInfo
+ // android.hardware.input.InputDeviceSensorInfo
+ FIND_CLASS(clazz, "android/hardware/input/InputSensorInfo");
+ gInputSensorInfo.clazz = reinterpret_cast<jclass>(env->NewGlobalRef(clazz));
+
+ GET_FIELD_ID(gInputSensorInfo.name, gInputSensorInfo.clazz, "mName", "Ljava/lang/String;");
+ GET_FIELD_ID(gInputSensorInfo.vendor, gInputSensorInfo.clazz, "mVendor", "Ljava/lang/String;");
+ GET_FIELD_ID(gInputSensorInfo.version, gInputSensorInfo.clazz, "mVersion", "I");
+ GET_FIELD_ID(gInputSensorInfo.handle, gInputSensorInfo.clazz, "mHandle", "I");
+ GET_FIELD_ID(gInputSensorInfo.maxRange, gInputSensorInfo.clazz, "mMaxRange", "F");
+ GET_FIELD_ID(gInputSensorInfo.resolution, gInputSensorInfo.clazz, "mResolution", "F");
+ GET_FIELD_ID(gInputSensorInfo.power, gInputSensorInfo.clazz, "mPower", "F");
+ GET_FIELD_ID(gInputSensorInfo.minDelay, gInputSensorInfo.clazz, "mMinDelay", "I");
+ GET_FIELD_ID(gInputSensorInfo.fifoReservedEventCount, gInputSensorInfo.clazz,
+ "mFifoReservedEventCount", "I");
+ GET_FIELD_ID(gInputSensorInfo.fifoMaxEventCount, gInputSensorInfo.clazz, "mFifoMaxEventCount",
+ "I");
+ GET_FIELD_ID(gInputSensorInfo.stringType, gInputSensorInfo.clazz, "mStringType",
+ "Ljava/lang/String;");
+ GET_FIELD_ID(gInputSensorInfo.requiredPermission, gInputSensorInfo.clazz, "mRequiredPermission",
+ "Ljava/lang/String;");
+ GET_FIELD_ID(gInputSensorInfo.maxDelay, gInputSensorInfo.clazz, "mMaxDelay", "I");
+ GET_FIELD_ID(gInputSensorInfo.flags, gInputSensorInfo.clazz, "mFlags", "I");
+ GET_FIELD_ID(gInputSensorInfo.type, gInputSensorInfo.clazz, "mType", "I");
+ GET_FIELD_ID(gInputSensorInfo.id, gInputSensorInfo.clazz, "mId", "I");
+
+ GET_METHOD_ID(gInputSensorInfo.init, gInputSensorInfo.clazz, "<init>", "()V");
return 0;
}
diff --git a/services/core/jni/com_android_server_powerstats_PowerStatsService.cpp b/services/core/jni/com_android_server_powerstats_PowerStatsService.cpp
new file mode 100644
index 0000000..f5b851f
--- /dev/null
+++ b/services/core/jni/com_android_server_powerstats_PowerStatsService.cpp
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "PowerStatsService"
+
+#include <android/hardware/power/stats/1.0/IPowerStats.h>
+#include <jni.h>
+#include <nativehelper/JNIHelp.h>
+
+#include <log/log.h>
+
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::power::stats::V1_0::EnergyData;
+using android::hardware::power::stats::V1_0::RailInfo;
+using android::hardware::power::stats::V1_0::Status;
+
+// ChannelInfo
+static jclass class_CI;
+static jmethodID method_CI_init;
+static jfieldID field_CI_channelId;
+static jfieldID field_CI_channelName;
+
+// EnergyMeasurement
+static jclass class_EM;
+static jmethodID method_EM_init;
+static jfieldID field_EM_channelId;
+static jfieldID field_EM_timestampMs;
+static jfieldID field_EM_durationMs;
+static jfieldID field_EM_energyUWs;
+
+// StateInfo
+static jclass class_SI;
+static jmethodID method_SI_init;
+static jfieldID field_SI_stateId;
+static jfieldID field_SI_stateName;
+
+// PowerEntityInfo
+static jclass class_PEI;
+static jmethodID method_PEI_init;
+static jfieldID field_PEI_powerEntityId;
+static jfieldID field_PEI_powerEntityName;
+static jfieldID field_PEI_states;
+
+// StateResidency
+static jclass class_SR;
+static jmethodID method_SR_init;
+static jfieldID field_SR_stateId;
+static jfieldID field_SR_totalTimeInStateMs;
+static jfieldID field_SR_totalStateEntryCount;
+static jfieldID field_SR_lastEntryTimestampMs;
+
+// StateResidencyResult
+static jclass class_SRR;
+static jmethodID method_SRR_init;
+static jfieldID field_SRR_powerEntityId;
+static jfieldID field_SRR_stateResidencyData;
+
+namespace android {
+
+static std::mutex gPowerStatsHalMutex;
+static sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHalV1_0_ptr = nullptr;
+
+static void deinitPowerStats() {
+ gPowerStatsHalV1_0_ptr = nullptr;
+}
+
+struct PowerStatsHalDeathRecipient : virtual public hardware::hidl_death_recipient {
+ virtual void serviceDied(uint64_t cookie,
+ const wp<android::hidl::base::V1_0::IBase> &who) override {
+ // The HAL just died. Reset all handles to HAL services.
+ std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
+ deinitPowerStats();
+ }
+};
+
+sp<PowerStatsHalDeathRecipient> gPowerStatsHalDeathRecipient = new PowerStatsHalDeathRecipient();
+
+static bool connectToPowerStatsHal() {
+ if (gPowerStatsHalV1_0_ptr == nullptr) {
+ gPowerStatsHalV1_0_ptr = android::hardware::power::stats::V1_0::IPowerStats::getService();
+
+ if (gPowerStatsHalV1_0_ptr == nullptr) {
+ ALOGE("Unable to get power.stats HAL service.");
+ return false;
+ }
+
+ // Link death recipient to power.stats service handle
+ hardware::Return<bool> linked =
+ gPowerStatsHalV1_0_ptr->linkToDeath(gPowerStatsHalDeathRecipient, 0);
+ if (!linked.isOk()) {
+ ALOGE("Transaction error in linking to power.stats HAL death: %s",
+ linked.description().c_str());
+ deinitPowerStats();
+ return false;
+ } else if (!linked) {
+ ALOGW("Unable to link to power.stats HAL death notifications");
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool checkResult(const Return<void> &ret, const char *function) {
+ if (!ret.isOk()) {
+ ALOGE("%s failed: requested HAL service not available. Description: %s", function,
+ ret.description().c_str());
+ if (ret.isDeadObject()) {
+ deinitPowerStats();
+ }
+ return false;
+ }
+ return true;
+}
+
+static jobjectArray nativeGetPowerEntityInfo(JNIEnv *env, jclass clazz) {
+ std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
+
+ if (!connectToPowerStatsHal()) {
+ ALOGE("nativeGetPowerEntityInfo failed to connect to power.stats HAL");
+ return nullptr;
+ }
+
+ jobjectArray powerEntityInfoArray = nullptr;
+ Return<void> ret = gPowerStatsHalV1_0_ptr->getPowerEntityInfo(
+ [&env, &powerEntityInfoArray](auto infos, auto status) {
+ if (status != Status::SUCCESS) {
+ ALOGE("Error getting power entity info");
+ } else {
+ powerEntityInfoArray = env->NewObjectArray(infos.size(), class_PEI, nullptr);
+ for (int i = 0; i < infos.size(); i++) {
+ jstring powerEntityName =
+ env->NewStringUTF(infos[i].powerEntityName.c_str());
+ jobject powerEntityInfo = env->NewObject(class_PEI, method_PEI_init);
+ env->SetIntField(powerEntityInfo, field_PEI_powerEntityId,
+ infos[i].powerEntityId);
+ env->SetObjectField(powerEntityInfo, field_PEI_powerEntityName,
+ powerEntityName);
+ env->SetObjectArrayElement(powerEntityInfoArray, i, powerEntityInfo);
+ env->DeleteLocalRef(powerEntityName);
+ env->DeleteLocalRef(powerEntityInfo);
+ }
+ }
+ });
+ if (!checkResult(ret, __func__)) {
+ return nullptr;
+ }
+
+ ret = gPowerStatsHalV1_0_ptr->getPowerEntityStateInfo(
+ {}, [&env, &powerEntityInfoArray](auto infos, auto status) {
+ if (status != Status::SUCCESS) {
+ ALOGE("Error getting power entity state info");
+ } else {
+ for (int i = 0; i < infos.size(); i++) {
+ jobjectArray stateInfoArray =
+ env->NewObjectArray(infos[i].states.size(), class_SI, nullptr);
+ for (int j = 0; j < infos[i].states.size(); j++) {
+ jstring powerEntityStateName = env->NewStringUTF(
+ infos[i].states[j].powerEntityStateName.c_str());
+ jobject stateInfo = env->NewObject(class_SI, method_SI_init);
+ env->SetIntField(stateInfo, field_SI_stateId,
+ infos[i].states[j].powerEntityStateId);
+ env->SetObjectField(stateInfo, field_SI_stateName,
+ powerEntityStateName);
+ env->SetObjectArrayElement(stateInfoArray, j, stateInfo);
+ env->DeleteLocalRef(powerEntityStateName);
+ env->DeleteLocalRef(stateInfo);
+ }
+
+ for (int j = 0; j < env->GetArrayLength(powerEntityInfoArray); j++) {
+ jobject powerEntityInfo =
+ env->GetObjectArrayElement(powerEntityInfoArray, j);
+ if (env->GetIntField(powerEntityInfo, field_PEI_powerEntityId) ==
+ infos[i].powerEntityId) {
+ env->SetObjectField(powerEntityInfo, field_PEI_states,
+ stateInfoArray);
+ env->SetObjectArrayElement(powerEntityInfoArray, j,
+ powerEntityInfo);
+ break;
+ }
+ }
+ }
+ }
+ });
+ if (!checkResult(ret, __func__)) {
+ return nullptr;
+ }
+
+ return powerEntityInfoArray;
+}
+
+static jobjectArray nativeGetStateResidency(JNIEnv *env, jclass clazz, jintArray powerEntityIds) {
+ std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
+
+ if (!connectToPowerStatsHal()) {
+ ALOGE("nativeGetStateResidency failed to connect to power.stats HAL");
+ return nullptr;
+ }
+
+ size_t powerEntityIdCount = env->GetArrayLength(powerEntityIds);
+ hidl_vec<uint32_t> powerEntityIdVector(powerEntityIdCount);
+
+ jint *powerEntityIdElements = env->GetIntArrayElements(powerEntityIds, 0);
+ for (int i = 0; i < powerEntityIdCount; i++) {
+ powerEntityIdVector[i] = powerEntityIdElements[i];
+ }
+ env->ReleaseIntArrayElements(powerEntityIds, powerEntityIdElements, 0);
+
+ jobjectArray stateResidencyResultArray = nullptr;
+ Return<void> ret = gPowerStatsHalV1_0_ptr->getPowerEntityStateResidencyData(
+ powerEntityIdVector, [&env, &stateResidencyResultArray](auto results, auto status) {
+ if (status != Status::SUCCESS) {
+ ALOGE("Error getting power entity state residency data");
+ } else {
+ stateResidencyResultArray =
+ env->NewObjectArray(results.size(), class_SRR, nullptr);
+ for (int i = 0; i < results.size(); i++) {
+ jobjectArray stateResidencyArray =
+ env->NewObjectArray(results[i].stateResidencyData.size(), class_SR,
+ nullptr);
+ for (int j = 0; j < results[i].stateResidencyData.size(); j++) {
+ jobject stateResidency = env->NewObject(class_SR, method_SR_init);
+ env->SetIntField(stateResidency, field_SR_stateId,
+ results[i].stateResidencyData[j].powerEntityStateId);
+ env->SetLongField(stateResidency, field_SR_totalTimeInStateMs,
+ results[i].stateResidencyData[j].totalTimeInStateMs);
+ env->SetLongField(stateResidency, field_SR_totalStateEntryCount,
+ results[i]
+ .stateResidencyData[j]
+ .totalStateEntryCount);
+ env->SetLongField(stateResidency, field_SR_lastEntryTimestampMs,
+ results[i]
+ .stateResidencyData[j]
+ .lastEntryTimestampMs);
+ env->SetObjectArrayElement(stateResidencyArray, j, stateResidency);
+ env->DeleteLocalRef(stateResidency);
+ }
+ jobject stateResidencyResult = env->NewObject(class_SRR, method_SRR_init);
+ env->SetIntField(stateResidencyResult, field_SRR_powerEntityId,
+ results[i].powerEntityId);
+ env->SetObjectField(stateResidencyResult, field_SRR_stateResidencyData,
+ stateResidencyArray);
+ env->SetObjectArrayElement(stateResidencyResultArray, i,
+ stateResidencyResult);
+ env->DeleteLocalRef(stateResidencyResult);
+ }
+ }
+ });
+ if (!checkResult(ret, __func__)) {
+ return nullptr;
+ }
+
+ return stateResidencyResultArray;
+}
+
+static jobjectArray nativeGetEnergyMeterInfo(JNIEnv *env, jclass clazz) {
+ std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
+
+ if (!connectToPowerStatsHal()) {
+ ALOGE("nativeGetEnergyMeterInfo failed to connect to power.stats HAL");
+ return nullptr;
+ }
+
+ jobjectArray channelInfoArray = nullptr;
+ Return<void> ret = gPowerStatsHalV1_0_ptr->getRailInfo(
+ [&env, &channelInfoArray](auto railInfo, auto status) {
+ if (status != Status::SUCCESS) {
+ ALOGW("Error getting rail info");
+ } else {
+ channelInfoArray = env->NewObjectArray(railInfo.size(), class_CI, nullptr);
+ for (int i = 0; i < railInfo.size(); i++) {
+ jstring channelName = env->NewStringUTF(railInfo[i].railName.c_str());
+ jobject channelInfo = env->NewObject(class_CI, method_CI_init);
+ env->SetIntField(channelInfo, field_CI_channelId, railInfo[i].index);
+ env->SetObjectField(channelInfo, field_CI_channelName, channelName);
+ env->SetObjectArrayElement(channelInfoArray, i, channelInfo);
+ env->DeleteLocalRef(channelName);
+ env->DeleteLocalRef(channelInfo);
+ }
+ }
+ });
+
+ if (!checkResult(ret, __func__)) {
+ ALOGE("getRailInfo failed");
+ return nullptr;
+ }
+
+ return channelInfoArray;
+}
+
+static jobjectArray nativeReadEnergyMeters(JNIEnv *env, jclass clazz, jintArray channelIds) {
+ std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
+
+ if (!connectToPowerStatsHal()) {
+ ALOGE("nativeGetEnergy failed to connect to power.stats HAL");
+ }
+
+ size_t channelIdCount = env->GetArrayLength(channelIds);
+ hidl_vec<uint32_t> channelIdVector(channelIdCount);
+
+ jint *channelIdElements = env->GetIntArrayElements(channelIds, 0);
+ for (int i = 0; i < channelIdCount; i++) {
+ channelIdVector[i] = channelIdElements[i];
+ }
+ env->ReleaseIntArrayElements(channelIds, channelIdElements, 0);
+
+ jobjectArray energyMeasurementArray = nullptr;
+ Return<void> ret =
+ gPowerStatsHalV1_0_ptr
+ ->getEnergyData(channelIdVector,
+ [&env, &energyMeasurementArray](auto energyData, auto status) {
+ if (status != Status::SUCCESS) {
+ ALOGW("Error getting energy data");
+ } else {
+ energyMeasurementArray =
+ env->NewObjectArray(energyData.size(), class_EM,
+ nullptr);
+ for (int i = 0; i < energyData.size(); i++) {
+ jobject energyMeasurement =
+ env->NewObject(class_EM, method_EM_init);
+ env->SetIntField(energyMeasurement,
+ field_EM_channelId,
+ energyData[i].index);
+ env->SetLongField(energyMeasurement,
+ field_EM_timestampMs,
+ energyData[i].timestamp);
+ env->SetLongField(energyMeasurement,
+ field_EM_durationMs, -1);
+ env->SetLongField(energyMeasurement,
+ field_EM_energyUWs,
+ energyData[i].energy);
+ env->SetObjectArrayElement(energyMeasurementArray,
+ i, energyMeasurement);
+ env->DeleteLocalRef(energyMeasurement);
+ }
+ }
+ });
+
+ if (!checkResult(ret, __func__)) {
+ ALOGE("getEnergyData failed");
+ return nullptr;
+ }
+
+ return energyMeasurementArray;
+}
+
+static jboolean nativeInit(JNIEnv *env, jclass clazz) {
+ std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
+
+ // ChannelInfo
+ jclass temp = env->FindClass("android/hardware/power/stats/ChannelInfo");
+ class_CI = (jclass)env->NewGlobalRef(temp);
+ method_CI_init = env->GetMethodID(class_CI, "<init>", "()V");
+ field_CI_channelId = env->GetFieldID(class_CI, "channelId", "I");
+ field_CI_channelName = env->GetFieldID(class_CI, "channelName", "Ljava/lang/String;");
+
+ // EnergyMeasurement
+ temp = env->FindClass("android/hardware/power/stats/EnergyMeasurement");
+ class_EM = (jclass)env->NewGlobalRef(temp);
+ method_EM_init = env->GetMethodID(class_EM, "<init>", "()V");
+ field_EM_channelId = env->GetFieldID(class_EM, "channelId", "I");
+ field_EM_timestampMs = env->GetFieldID(class_EM, "timestampMs", "J");
+ field_EM_durationMs = env->GetFieldID(class_EM, "durationMs", "J");
+ field_EM_energyUWs = env->GetFieldID(class_EM, "energyUWs", "J");
+
+ // StateInfo
+ temp = env->FindClass("android/hardware/power/stats/StateInfo");
+ class_SI = (jclass)env->NewGlobalRef(temp);
+ method_SI_init = env->GetMethodID(class_SI, "<init>", "()V");
+ field_SI_stateId = env->GetFieldID(class_SI, "stateId", "I");
+ field_SI_stateName = env->GetFieldID(class_SI, "stateName", "Ljava/lang/String;");
+
+ // PowerEntityInfo
+ temp = env->FindClass("android/hardware/power/stats/PowerEntityInfo");
+ class_PEI = (jclass)env->NewGlobalRef(temp);
+ method_PEI_init = env->GetMethodID(class_PEI, "<init>", "()V");
+ field_PEI_powerEntityId = env->GetFieldID(class_PEI, "powerEntityId", "I");
+ field_PEI_powerEntityName = env->GetFieldID(class_PEI, "powerEntityName", "Ljava/lang/String;");
+ field_PEI_states =
+ env->GetFieldID(class_PEI, "states", "[Landroid/hardware/power/stats/StateInfo;");
+
+ // StateResidency
+ temp = env->FindClass("android/hardware/power/stats/StateResidency");
+ class_SR = (jclass)env->NewGlobalRef(temp);
+ method_SR_init = env->GetMethodID(class_SR, "<init>", "()V");
+ field_SR_stateId = env->GetFieldID(class_SR, "stateId", "I");
+ field_SR_totalTimeInStateMs = env->GetFieldID(class_SR, "totalTimeInStateMs", "J");
+ field_SR_totalStateEntryCount = env->GetFieldID(class_SR, "totalStateEntryCount", "J");
+ field_SR_lastEntryTimestampMs = env->GetFieldID(class_SR, "lastEntryTimestampMs", "J");
+
+ // StateResidencyResult
+ temp = env->FindClass("android/hardware/power/stats/StateResidencyResult");
+ class_SRR = (jclass)env->NewGlobalRef(temp);
+ method_SRR_init = env->GetMethodID(class_SRR, "<init>", "()V");
+ field_SRR_powerEntityId = env->GetFieldID(class_SRR, "powerEntityId", "I");
+ field_SRR_stateResidencyData =
+ env->GetFieldID(class_SRR, "stateResidencyData",
+ "[Landroid/hardware/power/stats/StateResidency;");
+
+ if (!connectToPowerStatsHal()) {
+ ALOGE("nativeInit failed to connect to power.stats HAL");
+ return false;
+ }
+
+ return true;
+}
+
+static const JNINativeMethod method_table[] = {
+ {"nativeInit", "()Z", (void *)nativeInit},
+ {"nativeGetPowerEntityInfo", "()[Landroid/hardware/power/stats/PowerEntityInfo;",
+ (void *)nativeGetPowerEntityInfo},
+ {"nativeGetStateResidency", "([I)[Landroid/hardware/power/stats/StateResidencyResult;",
+ (void *)nativeGetStateResidency},
+ {"nativeGetEnergyMeterInfo", "()[Landroid/hardware/power/stats/ChannelInfo;",
+ (void *)nativeGetEnergyMeterInfo},
+ {"nativeReadEnergyMeters", "([I)[Landroid/hardware/power/stats/EnergyMeasurement;",
+ (void *)nativeReadEnergyMeters},
+};
+
+int register_android_server_PowerStatsService(JNIEnv *env) {
+ return jniRegisterNativeMethods(env,
+ "com/android/server/powerstats/"
+ "PowerStatsHALWrapper$PowerStatsHAL10WrapperImpl",
+ method_table, NELEM(method_table));
+}
+
+}; // namespace android
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 5a0d08a..85ef394 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -29,6 +29,7 @@
int register_android_server_InputManager(JNIEnv* env);
int register_android_server_LightsService(JNIEnv* env);
int register_android_server_PowerManagerService(JNIEnv* env);
+int register_android_server_PowerStatsService(JNIEnv* env);
int register_android_server_storage_AppFuse(JNIEnv* env);
int register_android_server_SerialService(JNIEnv* env);
int register_android_server_SystemServer(JNIEnv* env);
@@ -82,6 +83,7 @@
register_android_server_broadcastradio_BroadcastRadioService(env);
register_android_server_broadcastradio_Tuner(vm, env);
register_android_server_PowerManagerService(env);
+ register_android_server_PowerStatsService(env);
register_android_server_SerialService(env);
register_android_server_InputManager(env);
register_android_server_LightsService(env);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
index c766ca0..7ec5ff0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
@@ -413,7 +413,6 @@
policy.mPermissionPolicy = permissionPolicy;
}
- parser.next();
int outerDepth = parser.getDepth();
policy.mLockTaskPackages.clear();
policy.mAdminList.clear();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 38eb373..0e0fe4c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -199,7 +199,6 @@
import android.media.IAudioService;
import android.net.ConnectivityManager;
import android.net.IIpConnectivityMetrics;
-import android.net.NetworkUtils;
import android.net.ProxyInfo;
import android.net.Uri;
import android.net.metrics.IpConnectivityLog;
@@ -270,6 +269,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.net.NetworkUtilsInternal;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BackgroundThread;
import com.android.internal.statusbar.IStatusBarService;
@@ -1025,23 +1025,6 @@
mSafetyChecker = new OneTimeSafetyChecker(this, operation, safe);
}
- // TODO(b/175392542): remove if not needed by ManagedProvisioning app anymore
- @Override
- public void factoryReset(String reason) {
- Preconditions.checkCallAuthorization(
- hasCallingOrSelfPermission(permission.MASTER_CLEAR));
- Slog.w(LOG_TAG, "factoryReset(): " + reason);
- final long identity = Binder.clearCallingIdentity();
- try {
- FactoryResetter.newBuilder(mContext).setReason(reason).build().factoryReset();
- } catch (IOException e) {
- // Shouldn't happen.
- Slog.wtf(LOG_TAG, "Could not factory reset", e);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
/**
* Unit test will subclass it to inject mocks.
*/
@@ -6175,6 +6158,7 @@
(admin != null) || hasCallingOrSelfPermission(permission.MASTER_CLEAR),
"No active admin for user %d and caller %d does not hold MASTER_CLEAR permission",
caller.getUserId(), caller.getUid());
+ checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_WIPE_DATA);
if (TextUtils.isEmpty(wipeReasonForUser)) {
if (calledByProfileOwnerOnOrgOwnedDevice && !calledOnParentInstance) {
@@ -9812,6 +9796,7 @@
Objects.requireNonNull(who, "ComponentName is null");
final CallerIdentity caller = getCallerIdentity(who);
Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
+ checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_LOGOUT_USER);
final int callingUserId = caller.getUserId();
synchronized (getLockObject()) {
@@ -9997,6 +9982,7 @@
throw new SecurityException("Profile owner cannot set user restriction " + key);
}
}
+ checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_USER_RESTRICTION);
// Save the restriction to ActiveAdmin.
final Bundle restrictions = activeAdmin.ensureUserRestrictions();
@@ -11780,13 +11766,8 @@
}
@Override
- public ComponentName getProfileOwnerAsUser(@UserIdInt int userId) {
- return DevicePolicyManagerService.this.getProfileOwnerAsUser(userId);
- }
-
- @Override
- public int getDeviceOwnerUserId() {
- return DevicePolicyManagerService.this.getDeviceOwnerUserId();
+ public ComponentName getProfileOwnerAsUser(int userHandle) {
+ return DevicePolicyManagerService.this.getProfileOwnerAsUser(userHandle);
}
@Override
@@ -14638,7 +14619,7 @@
return PRIVATE_DNS_SET_NO_ERROR;
case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME:
if (TextUtils.isEmpty(privateDnsHost)
- || !NetworkUtils.isWeaklyValidatedHostname(privateDnsHost)) {
+ || !NetworkUtilsInternal.isWeaklyValidatedHostname(privateDnsHost)) {
throw new IllegalArgumentException(
String.format("Provided hostname %s is not valid", privateDnsHost));
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
index 9f895c6..99693d2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
@@ -36,7 +36,6 @@
import android.util.Log;
import android.util.SparseArray;
import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.InstrumentationRegistry;
@@ -53,7 +52,6 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
/**
* Tests app ops version upgrades
@@ -183,8 +181,7 @@
boolean parse() {
try (FileInputStream stream = new FileInputStream(mFile)) {
- TypedXmlPullParser parser = Xml.newFastPullParser();
- parser.setInput(stream, StandardCharsets.UTF_8.name());
+ TypedXmlPullParser parser = Xml.resolvePullParser(stream);
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG
&& type != XmlPullParser.END_DOCUMENT) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/OWNERS b/services/tests/mockingservicestests/src/com/android/server/location/OWNERS
new file mode 100644
index 0000000..696a0c2
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/location/OWNERS
@@ -0,0 +1 @@
+file:/location/java/android/location/OWNERS
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java
index 98fd1c9..2b21cc5 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java
@@ -43,9 +43,9 @@
import android.location.GnssAntennaInfo.SphericalCorrections;
import android.location.GnssClock;
import android.location.GnssMeasurementCorrections;
+import android.location.GnssMeasurementRequest;
import android.location.GnssMeasurementsEvent;
import android.location.GnssNavigationMessage;
-import android.location.GnssRequest;
import android.location.GnssSingleSatCorrection;
import android.location.IGnssAntennaInfoListener;
import android.location.IGnssMeasurementsListener;
@@ -403,7 +403,7 @@
assertThrows(SecurityException.class,
() -> mGnssManagerService.addGnssMeasurementsListener(
- new GnssRequest.Builder().build(), mockGnssMeasurementsListener,
+ new GnssMeasurementRequest.Builder().build(), mockGnssMeasurementsListener,
TEST_PACKAGE, null));
mTestGnssMeasurementsProvider.onMeasurementsAvailable(gnssMeasurementsEvent);
@@ -422,7 +422,7 @@
enableLocationPermissions();
mGnssManagerService.addGnssMeasurementsListener(
- new GnssRequest.Builder().build(),
+ new GnssMeasurementRequest.Builder().build(),
mockGnssMeasurementsListener,
TEST_PACKAGE, null);
@@ -470,7 +470,8 @@
enableLocationPermissions();
- mGnssManagerService.addGnssMeasurementsListener(new GnssRequest.Builder().build(),
+ mGnssManagerService.addGnssMeasurementsListener(
+ new GnssMeasurementRequest.Builder().build(),
mockGnssMeasurementsListener,
TEST_PACKAGE, null);
@@ -494,7 +495,8 @@
enableLocationPermissions();
- mGnssManagerService.addGnssMeasurementsListener(new GnssRequest.Builder().build(),
+ mGnssManagerService.addGnssMeasurementsListener(
+ new GnssMeasurementRequest.Builder().build(),
mockGnssMeasurementsListener,
TEST_PACKAGE, null);
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index edae08a3..015eead 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -68,12 +68,12 @@
import com.android.server.testutils.mock
import com.android.server.testutils.nullable
import com.android.server.testutils.whenever
+import com.android.server.utils.WatchedArrayMap
import org.junit.Assert
import org.junit.rules.TestRule
import org.junit.runner.Description
import org.junit.runners.model.Statement
import org.mockito.AdditionalMatchers.or
-import org.mockito.invocation.InvocationOnMock
import org.mockito.quality.Strictness
import java.io.File
import java.io.IOException
@@ -114,7 +114,7 @@
private val mPreExistingSettings = ArrayMap<String, PackageSetting>()
/** The active map simulating the in memory storage of Settings */
- private val mSettingsMap = ArrayMap<String, PackageSetting>()
+ private val mSettingsMap = WatchedArrayMap<String, PackageSetting>()
init {
val apply = ExtendedMockito.mockitoSession()
@@ -268,7 +268,7 @@
wheneverStatic { Environment.getPackageCacheDirectory() }.thenReturn(packageCacheDirectory)
wheneverStatic { SystemProperties.digestOf("ro.build.fingerprint") }.thenReturn("cacheName")
wheneverStatic { Environment.getRootDirectory() }.thenReturn(rootDirectory)
- wheneverStatic { SystemServerInitThreadPool.submit(any(Runnable::class.java), anyString())}
+ wheneverStatic { SystemServerInitThreadPool.submit(any(Runnable::class.java), anyString()) }
.thenAnswer { FutureTask<Any?>(it.getArgument(0), null) }
wheneverStatic { Environment.getDataDirectory() }.thenReturn(dataAppDirectory.parentFile)
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/OWNERS b/services/tests/mockingservicestests/src/com/android/server/pm/OWNERS
new file mode 100644
index 0000000..d825dfd
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
index 68adacd..32ca7b5 100644
--- a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
@@ -172,6 +172,7 @@
@After
public void tearDown() throws Exception {
+ InputManager.clearInstance();
LocalServices.removeServiceForTest(PackageManagerInternal.class);
LocalServices.removeServiceForTest(PowerManagerInternal.class);
}
@@ -838,7 +839,7 @@
private InputDevice createInputDeviceWithVibrator(int id) {
return new InputDevice(id, 0, 0, "name", 0, 0, "description", false, 0, 0,
- null, /* hasVibrator= */ true, false, false);
+ null, /* hasVibrator= */ true, false, false, false /* hasSensor */);
}
private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
diff --git a/services/tests/servicestests/src/com/android/server/audio/OWNERS b/services/tests/servicestests/src/com/android/server/audio/OWNERS
new file mode 100644
index 0000000..894a1f5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/audio/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/audio/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index e588370..8c63bfc 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -190,6 +190,22 @@
}
@Test
+ public void testIsChangeEnabledForInvalidApp() throws Exception {
+ final long disabledChangeId = 1234L;
+ final long enabledChangeId = 1235L;
+ final long targetSdkChangeId = 1236L;
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addEnabledChangeWithId(enabledChangeId)
+ .addDisabledChangeWithId(disabledChangeId)
+ .addEnableSinceSdkChangeWithId(42, targetSdkChangeId)
+ .build();
+
+ assertThat(compatConfig.isChangeEnabled(enabledChangeId, null)).isTrue();
+ assertThat(compatConfig.isChangeEnabled(disabledChangeId, null)).isFalse();
+ assertThat(compatConfig.isChangeEnabled(targetSdkChangeId, null)).isTrue();
+ }
+
+ @Test
public void testPreventAddOverride() throws Exception {
final long changeId = 1234L;
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
index 64014ba..1d3b643 100644
--- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
@@ -107,18 +107,20 @@
mCompatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
.addEnabledChangeWithId(1L)
.addDisabledChangeWithIdAndName(2L, "change2")
- .addEnableAfterSdkChangeWithIdAndDescription(Build.VERSION_CODES.O, 3L, "desc")
- .addEnableAfterSdkChangeWithId(Build.VERSION_CODES.P, 4L)
- .addEnableAfterSdkChangeWithId(Build.VERSION_CODES.Q, 5L)
- .addEnableAfterSdkChangeWithId(Build.VERSION_CODES.R, 6L)
+ .addEnableSinceSdkChangeWithIdAndDescription(Build.VERSION_CODES.O, 3L, "desc")
+ .addEnableSinceSdkChangeWithId(Build.VERSION_CODES.P, 4L)
+ .addEnableSinceSdkChangeWithId(Build.VERSION_CODES.Q, 5L)
+ .addEnableSinceSdkChangeWithId(Build.VERSION_CODES.R, 6L)
.addLoggingOnlyChangeWithId(7L)
.build();
mPlatformCompat = new PlatformCompat(mContext, mCompatConfig);
assertThat(mPlatformCompat.listUIChanges()).asList().containsExactly(
new CompatibilityChangeInfo(1L, "", -1, -1, false, false, ""),
new CompatibilityChangeInfo(2L, "change2", -1, -1, true, false, ""),
- new CompatibilityChangeInfo(4L, "", Build.VERSION_CODES.P, -1, false, false, ""),
- new CompatibilityChangeInfo(5L, "", Build.VERSION_CODES.Q, -1, false, false, ""));
+ new CompatibilityChangeInfo(5L, "", /*enableAfter*/ -1,
+ /*enableSince*/ Build.VERSION_CODES.Q, false, false, ""),
+ new CompatibilityChangeInfo(6L, "", /*enableAfter*/ -1,
+ /*enableSince*/ Build.VERSION_CODES.R, false, false, ""));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/TransferOwnershipMetadataManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/TransferOwnershipMetadataManagerTest.java
index 07ea855..2d76537 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/TransferOwnershipMetadataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/TransferOwnershipMetadataManagerTest.java
@@ -37,6 +37,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -83,6 +84,7 @@
}
@Test
+ @Ignore
public void testFileContentValid() {
TransferOwnershipMetadataManager paramsManager = getOwnerTransferParams();
assertThat(paramsManager.saveMetadataFile(TEST_PARAMS)).isTrue();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
index 227e8c7..e5bcedb 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
@@ -77,6 +77,15 @@
+ " </allowed-values>"
+ " <default-value int-value=\"1\" />"
+ " </setting>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ "</cec-settings>";
FakeHdmiCecConfig(@NonNull Context context) {
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index f7d52b6..7aea4ff 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -1334,4 +1334,31 @@
assertThat(mNativeWrapper.getResultMessages()).contains(userControlReleased);
assertThat(mStandby).isFalse();
}
+
+ @Test
+ public void shouldHandleTvPowerKey_CecDisabled() {
+ mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+ HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+ assertThat(mHdmiControlService.shouldHandleTvPowerKey()).isFalse();
+ }
+
+ @Test
+ public void shouldHandleTvPowerKey_PowerControlModeNone() {
+ mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
+ HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+ HdmiControlManager.POWER_CONTROL_MODE_NONE);
+ assertThat(mHdmiControlService.shouldHandleTvPowerKey()).isFalse();
+ }
+
+ @Test
+ public void shouldHandleTvPowerKey_CecEnabled_PowerControlModeTv() {
+ mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+ HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+ mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
+ HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+ HdmiControlManager.POWER_CONTROL_MODE_TV);
+ assertThat(mHdmiControlService.shouldHandleTvPowerKey()).isTrue();
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index d24b376..81f55d8 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -192,4 +192,15 @@
assertThat(mHdmiControlService.getActiveSource().getPhysicalAddress()).isEqualTo(
externalDevice.getPhysicalAddress());
}
+
+ @Test
+ public void shouldHandleTvPowerKey_CecEnabled_PowerControlModeTv() {
+ mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+ HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+ mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().setStringValue(
+ HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+ HdmiControlManager.POWER_CONTROL_MODE_TV);
+ assertThat(mHdmiControlService.shouldHandleTvPowerKey()).isFalse();
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
index 20f9b70..e3e7768 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
@@ -28,7 +28,6 @@
import android.content.om.OverlayInfo;
import android.text.TextUtils;
import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.runner.AndroidJUnit4;
@@ -40,7 +39,7 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.io.StringReader;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -287,7 +286,7 @@
public void testPersistEmpty() throws Exception {
ByteArrayOutputStream os = new ByteArrayOutputStream();
mSettings.persist(os);
- String xml = new String(os.toByteArray(), "utf-8");
+ ByteArrayInputStream xml = new ByteArrayInputStream(os.toByteArray());
assertEquals(1, countXmlTags(xml, "overlays"));
assertEquals(0, countXmlTags(xml, "item"));
@@ -300,7 +299,7 @@
ByteArrayOutputStream os = new ByteArrayOutputStream();
mSettings.persist(os);
- final String xml = new String(os.toByteArray(), "utf-8");
+ ByteArrayInputStream xml = new ByteArrayInputStream(os.toByteArray());
assertEquals(1, countXmlTags(xml, "overlays"));
assertEquals(2, countXmlTags(xml, "item"));
@@ -319,7 +318,7 @@
ByteArrayOutputStream os = new ByteArrayOutputStream();
mSettings.persist(os);
- String xml = new String(os.toByteArray(), "utf-8");
+ ByteArrayInputStream xml = new ByteArrayInputStream(os.toByteArray());
assertEquals(1, countXmlTags(xml, "overlays"));
assertEquals(2, countXmlTags(xml, "item"));
@@ -338,7 +337,7 @@
ByteArrayOutputStream os = new ByteArrayOutputStream();
mSettings.persist(os);
- String xml = new String(os.toByteArray(), "utf-8");
+ ByteArrayInputStream xml = new ByteArrayInputStream(os.toByteArray());
assertEquals(1, countXmlAttributesWhere(xml, "item", "isEnabled", "true"));
}
@@ -391,8 +390,7 @@
ByteArrayOutputStream os = new ByteArrayOutputStream();
mSettings.persist(os);
- String xml = new String(os.toByteArray(), "utf-8");
- ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes("utf-8"));
+ ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
OverlayManagerSettings newSettings = new OverlayManagerSettings();
newSettings.restore(is);
@@ -403,10 +401,10 @@
assertEquals(OVERLAY_B1, b);
}
- private int countXmlTags(String xml, String tagToLookFor) throws Exception {
+ private int countXmlTags(InputStream in, String tagToLookFor) throws Exception {
+ in.reset();
int count = 0;
- TypedXmlPullParser parser = Xml.newFastPullParser();
- parser.setInput(new StringReader(xml));
+ TypedXmlPullParser parser = Xml.resolvePullParser(in);
int event = parser.getEventType();
while (event != XmlPullParser.END_DOCUMENT) {
if (event == XmlPullParser.START_TAG && tagToLookFor.equals(parser.getName())) {
@@ -417,11 +415,11 @@
return count;
}
- private int countXmlAttributesWhere(String xml, String tag, String attr, String value)
+ private int countXmlAttributesWhere(InputStream in, String tag, String attr, String value)
throws Exception {
+ in.reset();
int count = 0;
- TypedXmlPullParser parser = Xml.newFastPullParser();
- parser.setInput(new StringReader(xml));
+ TypedXmlPullParser parser = Xml.resolvePullParser(in);
int event = parser.getEventType();
while (event != XmlPullParser.END_DOCUMENT) {
if (event == XmlPullParser.START_TAG && tag.equals(parser.getName())) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index eec7d12..205548c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -52,6 +52,7 @@
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.utils.WatchableTester;
import org.junit.Before;
import org.junit.Test;
@@ -884,6 +885,104 @@
contains(hasProviderAppId, queriesProviderAppId));
}
+ @Test
+ public void testOnChangeReport() throws Exception {
+ final AppsFilter appsFilter =
+ new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ mMockExecutor);
+ final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
+ watcher.register();
+ simulateAddBasicAndroid(appsFilter);
+ watcher.verifyChangeReported("addBasic");
+ appsFilter.onSystemReady();
+ watcher.verifyChangeReported("systemReady");
+
+ final int systemAppId = Process.FIRST_APPLICATION_UID - 1;
+ final int seesNothingAppId = Process.FIRST_APPLICATION_UID;
+ final int hasProviderAppId = Process.FIRST_APPLICATION_UID + 1;
+ final int queriesProviderAppId = Process.FIRST_APPLICATION_UID + 2;
+
+ PackageSetting system = simulateAddPackage(appsFilter, pkg("some.system.pkg"), systemAppId);
+ watcher.verifyChangeReported("addPackage");
+ PackageSetting seesNothing = simulateAddPackage(appsFilter, pkg("com.some.package"),
+ seesNothingAppId);
+ watcher.verifyChangeReported("addPackage");
+ PackageSetting hasProvider = simulateAddPackage(appsFilter,
+ pkgWithProvider("com.some.other.package", "com.some.authority"), hasProviderAppId);
+ watcher.verifyChangeReported("addPackage");
+ PackageSetting queriesProvider = simulateAddPackage(appsFilter,
+ pkgQueriesProvider("com.yet.some.other.package", "com.some.authority"),
+ queriesProviderAppId);
+ watcher.verifyChangeReported("addPackage");
+
+ final SparseArray<int[]> systemFilter =
+ appsFilter.getVisibilityAllowList(system, USER_ARRAY, mExisting);
+ assertThat(toList(systemFilter.get(SYSTEM_USER)),
+ contains(seesNothingAppId, hasProviderAppId, queriesProviderAppId));
+ watcher.verifyNoChangeReported("get");
+
+ final SparseArray<int[]> seesNothingFilter =
+ appsFilter.getVisibilityAllowList(seesNothing, USER_ARRAY, mExisting);
+ assertThat(toList(seesNothingFilter.get(SYSTEM_USER)),
+ contains(seesNothingAppId));
+ assertThat(toList(seesNothingFilter.get(SECONDARY_USER)),
+ contains(seesNothingAppId));
+ watcher.verifyNoChangeReported("get");
+
+ final SparseArray<int[]> hasProviderFilter =
+ appsFilter.getVisibilityAllowList(hasProvider, USER_ARRAY, mExisting);
+ assertThat(toList(hasProviderFilter.get(SYSTEM_USER)),
+ contains(hasProviderAppId, queriesProviderAppId));
+ watcher.verifyNoChangeReported("get");
+
+ SparseArray<int[]> queriesProviderFilter =
+ appsFilter.getVisibilityAllowList(queriesProvider, USER_ARRAY, mExisting);
+ assertThat(toList(queriesProviderFilter.get(SYSTEM_USER)),
+ contains(queriesProviderAppId));
+ watcher.verifyNoChangeReported("get");
+
+ // provider read
+ appsFilter.grantImplicitAccess(hasProviderAppId, queriesProviderAppId);
+ watcher.verifyChangeReported("grantImplicitAccess");
+
+ // ensure implicit access is included in the filter
+ queriesProviderFilter =
+ appsFilter.getVisibilityAllowList(queriesProvider, USER_ARRAY, mExisting);
+ assertThat(toList(queriesProviderFilter.get(SYSTEM_USER)),
+ contains(hasProviderAppId, queriesProviderAppId));
+ watcher.verifyNoChangeReported("get");
+
+ // remove a package
+ appsFilter.removePackage(seesNothing);
+ watcher.verifyChangeReported("removePackage");
+ }
+
+ @Test
+ public void testOnChangeReportedFilter() throws Exception {
+ final AppsFilter appsFilter =
+ new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ mMockExecutor);
+ simulateAddBasicAndroid(appsFilter);
+ appsFilter.onSystemReady();
+ final WatchableTester watcher = new WatchableTester(appsFilter, "onChange filter");
+ watcher.register();
+
+ PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
+ DUMMY_TARGET_APPID);
+ PackageSetting instrumentation = simulateAddPackage(appsFilter,
+ pkgWithInstrumentation("com.some.other.package", "com.some.package"),
+ DUMMY_CALLING_APPID);
+ watcher.verifyChangeReported("addPackage");
+
+ assertFalse(
+ appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, instrumentation, target,
+ SYSTEM_USER));
+ assertFalse(
+ appsFilter.shouldFilterApplication(DUMMY_TARGET_APPID, target, instrumentation,
+ SYSTEM_USER));
+ watcher.verifyNoChangeReported("shouldFilterApplication");
+ }
+
private List<Integer> toList(int[] array) {
ArrayList<Integer> ret = new ArrayList<>(array.length);
for (int i = 0; i < array.length; i++) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 4b90a5c..282047a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -62,6 +62,7 @@
import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.permission.LegacyPermissionDataProvider;
+import com.android.server.utils.WatchableTester;
import com.google.common.truth.Truth;
@@ -178,6 +179,12 @@
PackageSetting ps = settings.getPackageLPr(PACKAGE_NAME_2);
assertThat(ps.getEnabled(0), is(COMPONENT_ENABLED_STATE_DISABLED_USER));
assertThat(ps.getEnabled(1), is(COMPONENT_ENABLED_STATE_DEFAULT));
+
+ // Verify that the snapshot passes the same test
+ Settings snapshot = settings.snapshot();
+ ps = snapshot.getPackageLPr(PACKAGE_NAME_2);
+ assertThat(ps.getEnabled(0), is(COMPONENT_ENABLED_STATE_DISABLED_USER));
+ assertThat(ps.getEnabled(1), is(COMPONENT_ENABLED_STATE_DEFAULT));
}
private static PersistableBundle createPersistableBundle(String packageName, long longVal,
@@ -197,21 +204,41 @@
final Context context = InstrumentationRegistry.getTargetContext();
final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null,
lock);
+ final WatchableTester watcher =
+ new WatchableTester(settingsUnderTest, "noSuspendingPackage");
+ watcher.register();
settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
+ watcher.verifyChangeReported("put package 1");
+ // Collect a snapshot at the midway point (package 2 has not been added)
+ final Settings snapshot = settingsUnderTest.snapshot();
+ watcher.verifyNoChangeReported("snapshot");
settingsUnderTest.mPackages.put(PACKAGE_NAME_2, createPackageSetting(PACKAGE_NAME_2));
+ watcher.verifyChangeReported("put package 2");
settingsUnderTest.readPackageRestrictionsLPr(0);
- final PackageSetting ps1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1);
- final PackageUserState packageUserState1 = ps1.readUserState(0);
+ PackageSetting ps1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1);
+ PackageUserState packageUserState1 = ps1.readUserState(0);
assertThat(packageUserState1.suspended, is(true));
assertThat(packageUserState1.suspendParams.size(), is(1));
assertThat(packageUserState1.suspendParams.keyAt(0), is("android"));
assertThat(packageUserState1.suspendParams.valueAt(0), is(nullValue()));
- final PackageSetting ps2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2);
- final PackageUserState packageUserState2 = ps2.readUserState(0);
+ // Verify that the snapshot returns the same answers
+ ps1 = snapshot.mPackages.get(PACKAGE_NAME_1);
+ packageUserState1 = ps1.readUserState(0);
+ assertThat(packageUserState1.suspended, is(true));
+ assertThat(packageUserState1.suspendParams.size(), is(1));
+ assertThat(packageUserState1.suspendParams.keyAt(0), is("android"));
+ assertThat(packageUserState1.suspendParams.valueAt(0), is(nullValue()));
+
+ PackageSetting ps2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2);
+ PackageUserState packageUserState2 = ps2.readUserState(0);
assertThat(packageUserState2.suspended, is(false));
assertThat(packageUserState2.suspendParams, is(nullValue()));
+
+ // Verify that the snapshot returns different answers
+ ps2 = snapshot.mPackages.get(PACKAGE_NAME_2);
+ assertTrue(ps2 == null);
}
@Test
@@ -221,15 +248,23 @@
final Context context = InstrumentationRegistry.getTargetContext();
final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null,
lock);
+ final WatchableTester watcher =
+ new WatchableTester(settingsUnderTest, "noSuspendParamsMap");
+ watcher.register();
settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
+ watcher.verifyChangeReported("put package 1");
settingsUnderTest.readPackageRestrictionsLPr(0);
+ watcher.verifyChangeReported("readPackageRestrictions");
final PackageSetting ps1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1);
+ watcher.verifyNoChangeReported("get package 1");
final PackageUserState packageUserState1 = ps1.readUserState(0);
+ watcher.verifyNoChangeReported("readUserState");
assertThat(packageUserState1.suspended, is(true));
assertThat(packageUserState1.suspendParams.size(), is(1));
assertThat(packageUserState1.suspendParams.keyAt(0), is(PACKAGE_NAME_3));
final PackageUserState.SuspendParams params = packageUserState1.suspendParams.valueAt(0);
+ watcher.verifyNoChangeReported("fetch user state");
assertThat(params, is(notNullValue()));
assertThat(params.appExtras.size(), is(1));
assertThat(params.appExtras.getString("app_extra_string"), is("value"));
@@ -249,6 +284,8 @@
final Context context = InstrumentationRegistry.getTargetContext();
final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null,
new Object());
+ final WatchableTester watcher = new WatchableTester(settingsUnderTest, "suspendInfo");
+ watcher.register();
final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2);
final PackageSetting ps3 = createPackageSetting(PACKAGE_NAME_3);
@@ -283,33 +320,46 @@
ps1.addOrUpdateSuspension("suspendingPackage2", dialogInfo2, appExtras2, launcherExtras2,
0);
settingsUnderTest.mPackages.put(PACKAGE_NAME_1, ps1);
+ watcher.verifyChangeReported("put package 1");
ps2.addOrUpdateSuspension("suspendingPackage3", null, appExtras1, null, 0);
settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
+ watcher.verifyChangeReported("put package 2");
ps3.removeSuspension("irrelevant", 0);
settingsUnderTest.mPackages.put(PACKAGE_NAME_3, ps3);
+ watcher.verifyChangeReported("put package 3");
settingsUnderTest.writePackageRestrictionsLPr(0);
+ watcher.verifyChangeReported("writePackageRestrictions");
settingsUnderTest.mPackages.clear();
+ watcher.verifyChangeReported("clear packages");
settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
+ watcher.verifyChangeReported("put package 1");
settingsUnderTest.mPackages.put(PACKAGE_NAME_2, createPackageSetting(PACKAGE_NAME_2));
+ watcher.verifyChangeReported("put package 2");
settingsUnderTest.mPackages.put(PACKAGE_NAME_3, createPackageSetting(PACKAGE_NAME_3));
+ watcher.verifyChangeReported("put package 3");
// now read and verify
settingsUnderTest.readPackageRestrictionsLPr(0);
+ watcher.verifyChangeReported("readPackageRestrictions");
final PackageUserState readPus1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1)
.readUserState(0);
+ watcher.verifyNoChangeReported("package get 1");
assertThat(readPus1.suspended, is(true));
assertThat(readPus1.suspendParams.size(), is(2));
+ watcher.verifyNoChangeReported("read package param");
assertThat(readPus1.suspendParams.keyAt(0), is("suspendingPackage1"));
final PackageUserState.SuspendParams params11 = readPus1.suspendParams.valueAt(0);
+ watcher.verifyNoChangeReported("read package param");
assertThat(params11, is(notNullValue()));
assertThat(params11.dialogInfo, is(dialogInfo1));
assertThat(BaseBundle.kindofEquals(params11.appExtras, appExtras1), is(true));
assertThat(BaseBundle.kindofEquals(params11.launcherExtras, launcherExtras1),
is(true));
+ watcher.verifyNoChangeReported("read package param");
assertThat(readPus1.suspendParams.keyAt(1), is("suspendingPackage2"));
final PackageUserState.SuspendParams params12 = readPus1.suspendParams.valueAt(1);
@@ -318,6 +368,7 @@
assertThat(BaseBundle.kindofEquals(params12.appExtras, appExtras2), is(true));
assertThat(BaseBundle.kindofEquals(params12.launcherExtras, launcherExtras2),
is(true));
+ watcher.verifyNoChangeReported("read package param");
final PackageUserState readPus2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2)
.readUserState(0);
@@ -329,11 +380,13 @@
assertThat(params21.dialogInfo, is(nullValue()));
assertThat(BaseBundle.kindofEquals(params21.appExtras, appExtras1), is(true));
assertThat(params21.launcherExtras, is(nullValue()));
+ watcher.verifyNoChangeReported("read package param");
final PackageUserState readPus3 = settingsUnderTest.mPackages.get(PACKAGE_NAME_3)
.readUserState(0);
assertThat(readPus3.suspended, is(false));
assertThat(readPus3.suspendParams, is(nullValue()));
+ watcher.verifyNoChangeReported("package get 3");
}
@Test
@@ -467,14 +520,23 @@
final Object lock = new Object();
Settings settings = new Settings(context.getFilesDir(),
mRuntimePermissionsPersistence, mPermissionDataProvider, lock);
+ final WatchableTester watcher = new WatchableTester(settings, "testEnableDisable");
+ watcher.register();
assertThat(settings.readLPw(createFakeUsers()), is(true));
+ watcher.verifyChangeReported("readLPw");
// Enable/Disable a package
PackageSetting ps = settings.getPackageLPr(PACKAGE_NAME_1);
+ watcher.verifyNoChangeReported("getPackageLPr");
+ assertThat(ps.getEnabled(0), is(not(COMPONENT_ENABLED_STATE_DISABLED)));
+ assertThat(ps.getEnabled(1), is(not(COMPONENT_ENABLED_STATE_ENABLED)));
ps.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, 0, null);
+ watcher.verifyChangeReported("setEnabled DISABLED");
ps.setEnabled(COMPONENT_ENABLED_STATE_ENABLED, 1, null);
+ watcher.verifyChangeReported("setEnabled ENABLED");
assertThat(ps.getEnabled(0), is(COMPONENT_ENABLED_STATE_DISABLED));
assertThat(ps.getEnabled(1), is(COMPONENT_ENABLED_STATE_ENABLED));
+ watcher.verifyNoChangeReported("getEnabled");
// Enable/Disable a component
ArraySet<String> components = new ArraySet<String>();
@@ -1152,7 +1214,8 @@
private void verifyKeySetMetaData(Settings settings)
throws ReflectiveOperationException, IllegalAccessException {
- ArrayMap<String, PackageSetting> packages = settings.mPackages;
+ ArrayMap<String, PackageSetting> packages =
+ settings.mPackages.untrackedMap();
KeySetManagerService ksms = settings.mKeySetManagerService;
/* verify keyset and public key ref counts */
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java
index 583c3d4..7546c43 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java
@@ -25,8 +25,16 @@
import android.os.Bundle;
import android.os.PersistableBundle;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Xml;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
@SmallTest
+@RunWith(AndroidJUnit4.class)
public class ShortcutManagerTest4 extends BaseShortcutManagerTest {
private static Bundle sIntentExtras = makeBundle(
@@ -99,7 +107,10 @@
"x2", "value{?}"
);
+ @Test
public void testPersistingWeirdCharacters() {
+ Assume.assumeFalse(Xml.ENABLE_BINARY_DEFAULT);
+
final Intent intent = new Intent(Intent.ACTION_MAIN)
.putExtras(sIntentExtras);
diff --git a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
index b26d1efe..08d4caa 100644
--- a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
@@ -209,7 +209,7 @@
}
@Override
- public boolean initialize() {
+ public boolean isInitialized() {
return true;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
index fa8e367..ac93ff6 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
@@ -44,6 +44,7 @@
import androidx.test.InstrumentationRegistry;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -89,6 +90,11 @@
mContextSpy, new Handler(mTestLooper.getLooper()));
}
+ @After
+ public void tearDown() throws Exception {
+ InputManager.clearInstance();
+ }
+
@Test
public void onInputDeviceAdded_withSettingsDisabled_ignoresNewDevice() throws Exception {
when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[0]);
@@ -286,6 +292,6 @@
private InputDevice createInputDevice(int id, boolean hasVibrator) {
return new InputDevice(id, 0, 0, "name", 0, 0, "description", false, 0, 0,
- null, hasVibrator, false, false);
+ null, hasVibrator, false, false, false /* hasSensor */);
}
}
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 f7c655f..a18bce7 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -111,9 +111,9 @@
import android.content.ComponentName;
import android.content.ContentUris;
import android.content.Context;
-import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.IIntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
@@ -1501,6 +1501,20 @@
}
@Test
+ public void testCancelImmediatelyAfterEnqueueNotifiesListeners_ForegroundServiceFlag()
+ throws Exception {
+ final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
+ sbn.getNotification().flags =
+ Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE;
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
+ sbn.getId(), sbn.getNotification(), sbn.getUserId());
+ mBinderService.cancelNotificationWithTag(PKG, PKG, "tag", sbn.getId(), sbn.getUserId());
+ waitForIdle();
+ verify(mListeners, times(1)).notifyPostedLocked(any(), any());
+ verify(mListeners, times(1)).notifyRemovedLocked(any(), anyInt(), any());
+ }
+
+ @Test
public void testUserInitiatedClearAll_noLeak() throws Exception {
final NotificationRecord n = generateNotificationRecord(
mTestNotificationChannel, 1, "group", true);
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 466b861..801a27d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -248,7 +248,7 @@
int topPosition = taskDisplayArea.getRootTaskCount() - 1;
// Ensure the new alwaysOnTop stack is put below the pinned stack, but on top of the
// existing alwaysOnTop stack.
- assertEquals(topPosition - 1, taskDisplayArea.getIndexOf(anotherAlwaysOnTopStack));
+ assertEquals(topPosition - 1, taskDisplayArea.getTaskIndexOf(anotherAlwaysOnTopStack));
final Task nonAlwaysOnTopStack = taskDisplayArea.createRootTask(
WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -256,7 +256,7 @@
topPosition = taskDisplayArea.getRootTaskCount() - 1;
// Ensure the non-alwaysOnTop stack is put below the three alwaysOnTop stacks, but above the
// existing other non-alwaysOnTop stacks.
- assertEquals(topPosition - 3, taskDisplayArea.getIndexOf(nonAlwaysOnTopStack));
+ assertEquals(topPosition - 3, taskDisplayArea.getTaskIndexOf(nonAlwaysOnTopStack));
anotherAlwaysOnTopStack.setAlwaysOnTop(false);
taskDisplayArea.positionChildAt(POSITION_TOP, anotherAlwaysOnTopStack,
@@ -264,16 +264,16 @@
assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
// Ensure, when always on top is turned off for a stack, the stack is put just below all
// other always on top stacks.
- assertEquals(topPosition - 2, taskDisplayArea.getIndexOf(anotherAlwaysOnTopStack));
+ assertEquals(topPosition - 2, taskDisplayArea.getTaskIndexOf(anotherAlwaysOnTopStack));
anotherAlwaysOnTopStack.setAlwaysOnTop(true);
// Ensure always on top state changes properly when windowing mode changes.
anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
- assertEquals(topPosition - 2, taskDisplayArea.getIndexOf(anotherAlwaysOnTopStack));
+ assertEquals(topPosition - 2, taskDisplayArea.getTaskIndexOf(anotherAlwaysOnTopStack));
anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FREEFORM);
assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
- assertEquals(topPosition - 1, taskDisplayArea.getIndexOf(anotherAlwaysOnTopStack));
+ assertEquals(topPosition - 1, taskDisplayArea.getTaskIndexOf(anotherAlwaysOnTopStack));
final Task dreamStack = taskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_DREAM, true /* onTop */);
@@ -282,7 +282,7 @@
topPosition = taskDisplayArea.getRootTaskCount() - 1;
// Ensure dream shows above all activities, including PiP
assertEquals(dreamStack, taskDisplayArea.getTopRootTask());
- assertEquals(topPosition - 1, taskDisplayArea.getIndexOf(pinnedStack));
+ assertEquals(topPosition - 1, taskDisplayArea.getTaskIndexOf(pinnedStack));
final Task assistStack = taskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */);
@@ -295,7 +295,7 @@
final boolean isAssistantOnTop = mContext.getResources()
.getBoolean(com.android.internal.R.bool.config_assistantOnTopOfDream);
assertEquals(isAssistantOnTop ? topPosition : topPosition - 4,
- taskDisplayArea.getIndexOf(assistStack));
+ taskDisplayArea.getTaskIndexOf(assistStack));
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 2d71d7f..95a1b61 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -75,7 +75,6 @@
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
-import android.window.TaskSnapshot;
import android.app.ActivityOptions;
import android.app.WindowConfiguration;
import android.app.servertransaction.ActivityConfigurationChangeItem;
@@ -102,6 +101,7 @@
import android.view.RemoteAnimationTarget;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
+import android.window.TaskSnapshot;
import androidx.test.filters.MediumTest;
@@ -1662,7 +1662,8 @@
any() /* requestedVisibility */, any() /* outFrame */,
any() /* outDisplayCutout */, any() /* outInputChannel */,
any() /* outInsetsState */, any() /* outActiveControls */);
- TaskSnapshotSurface.create(mAtm.mWindowManager, activity, snapshot);
+ mAtm.mWindowManager.mStartingSurfaceController
+ .createTaskSnapshotSurface(activity, snapshot);
} catch (RemoteException ignored) {
} finally {
reset(session);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 5504460..8ea95ae 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -167,7 +167,7 @@
null /* task */);
// Assert that stack is at the bottom.
- assertEquals(0, mDefaultTaskDisplayArea.getIndexOf(primarySplitScreen));
+ assertEquals(0, mDefaultTaskDisplayArea.getTaskIndexOf(primarySplitScreen));
// Ensure no longer in splitscreen.
assertEquals(WINDOWING_MODE_FULLSCREEN, primarySplitScreen.getWindowingMode());
@@ -748,10 +748,10 @@
doReturn(false).when(fullscreenStack).isTranslucent(any());
// Ensure that we don't move the home stack if it is already behind the top fullscreen stack
- int homeStackIndex = mDefaultTaskDisplayArea.getIndexOf(homeStack);
+ int homeStackIndex = mDefaultTaskDisplayArea.getTaskIndexOf(homeStack);
assertEquals(fullscreenStack, getRootTaskAbove(homeStack));
mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeStack);
- assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getIndexOf(homeStack));
+ assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getTaskIndexOf(homeStack));
}
@Test
@@ -766,10 +766,10 @@
doReturn(true).when(fullscreenStack).isTranslucent(any());
// Ensure that we don't move the home stack if it is already behind the top fullscreen stack
- int homeStackIndex = mDefaultTaskDisplayArea.getIndexOf(homeStack);
+ int homeStackIndex = mDefaultTaskDisplayArea.getTaskIndexOf(homeStack);
assertEquals(fullscreenStack, getRootTaskAbove(homeStack));
mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeStack);
- assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getIndexOf(homeStack));
+ assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getTaskIndexOf(homeStack));
}
@Test
@@ -784,10 +784,10 @@
doReturn(false).when(fullscreenStack).isTranslucent(any());
// Ensure we don't move the home stack if it is already on top
- int homeStackIndex = mDefaultTaskDisplayArea.getIndexOf(homeStack);
+ int homeStackIndex = mDefaultTaskDisplayArea.getTaskIndexOf(homeStack);
assertNull(getRootTaskAbove(homeStack));
mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeStack);
- assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getIndexOf(homeStack));
+ assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getTaskIndexOf(homeStack));
}
@Test
@@ -853,9 +853,9 @@
doReturn(false).when(fullscreenStack2).isTranslucent(any());
// Ensure we don't move the home stack behind itself
- int homeStackIndex = mDefaultTaskDisplayArea.getIndexOf(homeStack);
+ int homeStackIndex = mDefaultTaskDisplayArea.getTaskIndexOf(homeStack);
mDefaultTaskDisplayArea.moveRootTaskBehindRootTask(homeStack, homeStack);
- assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getIndexOf(homeStack));
+ assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getTaskIndexOf(homeStack));
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 76e98ab..cde866b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -512,8 +512,8 @@
}
private void assertNoTasks(DisplayContent display) {
- display.forAllRootTasks(stack -> {
- assertFalse(stack.hasChild());
+ display.forAllRootTasks(rootTask -> {
+ assertFalse(rootTask.hasChild());
});
}
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 f7beb74..3beb7f2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
@@ -199,7 +199,7 @@
mHost.addChild(child, 0);
final float alpha = 0.8f;
- mDimmer.dimBelow(mTransaction, child, alpha);
+ mDimmer.dimBelow(mTransaction, child, alpha, 0);
SurfaceControl dimLayer = getDimLayer();
assertNotNull("Dimmer should have created a surface", dimLayer);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java
index 1198ee2..5597be9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
import static android.window.DisplayAreaOrganizer.FEATURE_ROOT;
import static android.window.DisplayAreaOrganizer.FEATURE_RUNTIME_TASK_CONTAINER_FIRST;
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
@@ -117,7 +118,7 @@
}
@Test
- public void testCreateTaskDisplayArea() {
+ public void testCreateTaskDisplayArea_topBelowRoot() {
final String newTdaName = "testTda";
final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
final DisplayAreaAppearedInfo tdaInfo = mOrganizerController.createTaskDisplayArea(
@@ -142,6 +143,30 @@
}
@Test
+ public void testCreateTaskDisplayArea_topBelowAnotherTaskDisplayArea() {
+ final String newTdaName = "testTda";
+ final TaskDisplayArea parentTda = mDisplayContent.getDefaultTaskDisplayArea();
+ final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
+ final DisplayAreaAppearedInfo tdaInfo = mOrganizerController.createTaskDisplayArea(
+ organizer, DEFAULT_DISPLAY, FEATURE_DEFAULT_TASK_CONTAINER, newTdaName);
+
+ final WindowContainer wc = parentTda.getChildAt(parentTda.getChildCount() - 1);
+
+ // A new TaskDisplayArea is created on the top.
+ assertThat(wc).isInstanceOf(TaskDisplayArea.class);
+ assertThat(tdaInfo.getDisplayAreaInfo().displayId).isEqualTo(DEFAULT_DISPLAY);
+ assertThat(tdaInfo.getDisplayAreaInfo().token)
+ .isEqualTo(wc.mRemoteToken.toWindowContainerToken());
+
+ final TaskDisplayArea tda = wc.asTaskDisplayArea();
+
+ assertThat(tda.getName()).isEqualTo(newTdaName);
+ assertThat(tda.mFeatureId).isEqualTo(tdaInfo.getDisplayAreaInfo().featureId);
+ assertThat(tda.mCreatedByOrganizer).isTrue();
+ assertThat(tda.mOrganizer).isEqualTo(organizer);
+ }
+
+ @Test
public void testCreateTaskDisplayArea_incrementalTdaFeatureId() {
final String newTdaName = "testTda";
final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
index fb585ed..b33bb7b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
@@ -41,7 +41,6 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
@@ -102,7 +101,6 @@
mRoot = new SurfacelessDisplayAreaRoot(mWms);
mImeContainer = new DisplayArea.Tokens(mWms, ABOVE_TASKS, "ImeContainer");
mDisplayContent = mock(DisplayContent.class);
- doReturn(true).when(mDisplayContent).isTrusted();
mDefaultTaskDisplayArea = new TaskDisplayArea(mDisplayContent, mWms, "Tasks",
FEATURE_DEFAULT_TASK_CONTAINER);
mTaskDisplayAreaList = new ArrayList<>();
@@ -702,7 +700,7 @@
private Map<DisplayArea<?>, Set<Integer>> calculateZSets(
DisplayAreaPolicyBuilder.Result policy,
DisplayArea.Tokens ime,
- DisplayArea<Task> tasks) {
+ TaskDisplayArea taskDisplayArea) {
Map<DisplayArea<?>, Set<Integer>> zSets = new HashMap<>();
int[] types = {TYPE_STATUS_BAR, TYPE_NAVIGATION_BAR, TYPE_PRESENTATION,
TYPE_APPLICATION_OVERLAY};
@@ -710,7 +708,7 @@
WindowToken token = tokenOfType(type);
recordLayer(policy.findAreaForToken(token), token.getWindowLayerFromType(), zSets);
}
- recordLayer(tasks, APPLICATION_LAYER, zSets);
+ recordLayer(taskDisplayArea, APPLICATION_LAYER, zSets);
recordLayer(ime, mPolicy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD), zSets);
return zSets;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java
index d451180..496b2b7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java
@@ -22,18 +22,15 @@
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import android.platform.test.annotations.Presubmit;
-import android.util.Pair;
-import android.view.Display;
-import android.view.DisplayInfo;
import androidx.test.filters.SmallTest;
@@ -41,8 +38,9 @@
import com.google.android.collect.Lists;
+import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
-import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.Collections;
@@ -56,65 +54,78 @@
*/
@SmallTest
@Presubmit
-@RunWith(WindowTestRunner.class)
-public class DisplayAreaPolicyTests extends WindowTestsBase {
+public class DisplayAreaPolicyTests {
+
+ @Rule
+ public final SystemServicesTestRule mSystemServices = new SystemServicesTestRule();
+
+ private DisplayAreaPolicyBuilder.Result mPolicy;
+ private TaskDisplayArea mTaskDisplayArea1;
+ private TaskDisplayArea mTaskDisplayArea2;
+ private RootDisplayArea mRoot;
+
+ @Before
+ public void setUp() throws Exception {
+ WindowManagerService wms = mSystemServices.getWindowManagerService();
+ mRoot = new SurfacelessDisplayAreaRoot(wms);
+ spyOn(mRoot);
+ DisplayArea.Tokens ime = new DisplayArea.Tokens(wms, ABOVE_TASKS, "Ime");
+ DisplayContent displayContent = mock(DisplayContent.class);
+ doReturn(true).when(displayContent).isTrusted();
+ mTaskDisplayArea1 = new TaskDisplayArea(displayContent, wms, "Tasks1",
+ FEATURE_DEFAULT_TASK_CONTAINER);
+ mTaskDisplayArea2 = new TaskDisplayArea(displayContent, wms, "Tasks2",
+ FEATURE_VENDOR_FIRST);
+ List<TaskDisplayArea> taskDisplayAreaList = new ArrayList<>();
+ taskDisplayAreaList.add(mTaskDisplayArea1);
+ taskDisplayAreaList.add(mTaskDisplayArea2);
+
+ mPolicy = new DisplayAreaPolicyBuilder()
+ .setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+ .setImeContainer(ime)
+ .setTaskDisplayAreas(taskDisplayAreaList))
+ .build(wms);
+ }
@Test
public void testGetDefaultTaskDisplayArea() {
- final Pair<DisplayAreaPolicy, List<TaskDisplayArea>> result =
- createPolicyWith2TaskDisplayAreas();
- final DisplayAreaPolicy policy = result.first;
- final TaskDisplayArea taskDisplayArea1 = result.second.get(0);
- assertEquals(taskDisplayArea1, policy.getDefaultTaskDisplayArea());
+ assertEquals(mTaskDisplayArea1, mPolicy.getDefaultTaskDisplayArea());
}
@Test
public void testTaskDisplayArea_taskPositionChanged_updatesTaskDisplayAreaPosition() {
- final Pair<DisplayAreaPolicy, List<TaskDisplayArea>> result =
- createPolicyWith2TaskDisplayAreas();
- final DisplayAreaPolicy policy = result.first;
- final TaskDisplayArea taskDisplayArea1 = result.second.get(0);
- final TaskDisplayArea taskDisplayArea2 = result.second.get(1);
- final Task stack1 = taskDisplayArea1.createRootTask(
+ final Task stack1 = mTaskDisplayArea1.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final Task stack2 = taskDisplayArea2.createRootTask(
+ final Task stack2 = mTaskDisplayArea2.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Initial order
- assertTaskDisplayAreasOrder(policy, taskDisplayArea1, taskDisplayArea2);
+ assertTaskDisplayAreasOrder(mPolicy, mTaskDisplayArea1, mTaskDisplayArea2);
// Move stack in tda1 to top
stack1.getParent().positionChildAt(POSITION_TOP, stack1, true /* includingParents */);
- assertTaskDisplayAreasOrder(policy, taskDisplayArea2, taskDisplayArea1);
+ assertTaskDisplayAreasOrder(mPolicy, mTaskDisplayArea2, mTaskDisplayArea1);
// Move stack in tda2 to top, but not including parents
stack2.getParent().positionChildAt(POSITION_TOP, stack2, false /* includingParents */);
- assertTaskDisplayAreasOrder(policy, taskDisplayArea2, taskDisplayArea1);
+ assertTaskDisplayAreasOrder(mPolicy, mTaskDisplayArea2, mTaskDisplayArea1);
// Move stack in tda1 to bottom
stack1.getParent().positionChildAt(POSITION_BOTTOM, stack1, true /* includingParents */);
- assertTaskDisplayAreasOrder(policy, taskDisplayArea1, taskDisplayArea2);
+ assertTaskDisplayAreasOrder(mPolicy, mTaskDisplayArea1, mTaskDisplayArea2);
// Move stack in tda2 to bottom, but not including parents
stack2.getParent().positionChildAt(POSITION_BOTTOM, stack2, false /* includingParents */);
- assertTaskDisplayAreasOrder(policy, taskDisplayArea1, taskDisplayArea2);
- }
-
- @Test
- public void testEmptyFeaturesOnUntrustedDisplay() {
- final DisplayInfo info = new DisplayInfo(mDisplayInfo);
- info.flags &= ~Display.FLAG_TRUSTED;
- final DisplayContent untrustedDisplay = new TestDisplayContent.Builder(mAtm, info).build();
- assertTrue(untrustedDisplay.mFeatures.isEmpty());
+ assertTaskDisplayAreasOrder(mPolicy, mTaskDisplayArea1, mTaskDisplayArea2);
}
@Test
public void testDisplayAreaGroup_taskPositionChanged_updatesDisplayAreaGroupPosition() {
- final WindowManagerService wms = mWm;
+ final WindowManagerService wms = mSystemServices.getWindowManagerService();
final DisplayContent displayContent = mock(DisplayContent.class);
doReturn(true).when(displayContent).isTrusted();
final RootDisplayArea root = new SurfacelessDisplayAreaRoot(wms);
@@ -192,24 +203,4 @@
}, false /* traverseTopToBottom */);
assertEquals(expectOrder, actualOrder);
}
-
- private Pair<DisplayAreaPolicy, List<TaskDisplayArea>> createPolicyWith2TaskDisplayAreas() {
- final SurfacelessDisplayAreaRoot root = new SurfacelessDisplayAreaRoot(mWm);
- final DisplayArea.Tokens ime = new DisplayArea.Tokens(mWm, ABOVE_TASKS, "Ime");
- final DisplayContent displayContent = mock(DisplayContent.class);
- doReturn(true).when(displayContent).isTrusted();
- final TaskDisplayArea taskDisplayArea1 = new TaskDisplayArea(displayContent, mWm, "Tasks1",
- FEATURE_DEFAULT_TASK_CONTAINER);
- final TaskDisplayArea taskDisplayArea2 = new TaskDisplayArea(displayContent, mWm, "Tasks2",
- FEATURE_VENDOR_FIRST);
- final List<TaskDisplayArea> taskDisplayAreaList = new ArrayList<>();
- taskDisplayAreaList.add(taskDisplayArea1);
- taskDisplayAreaList.add(taskDisplayArea2);
-
- return Pair.create(new DisplayAreaPolicyBuilder()
- .setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(root)
- .setImeContainer(ime)
- .setTaskDisplayAreas(taskDisplayAreaList))
- .build(mWm), taskDisplayAreaList);
- }
}
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 b451d9f..69b8ccf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -50,6 +50,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
@@ -106,6 +107,7 @@
import android.view.InsetsState;
import android.view.MotionEvent;
import android.view.Surface;
+import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.WindowManager;
@@ -1534,6 +1536,22 @@
}
@Test
+ public void testValidWindowingLayer() {
+ final SurfaceControl windowingLayer = mDisplayContent.getWindowingLayer();
+ assertNotNull(windowingLayer);
+
+ final List<DisplayArea<?>> windowedMagnificationAreas =
+ mDisplayContent.mDisplayAreaPolicy.getDisplayAreas(FEATURE_WINDOWED_MAGNIFICATION);
+ if (windowedMagnificationAreas != null) {
+ assertEquals("There should be only one DisplayArea for FEATURE_WINDOWED_MAGNIFICATION",
+ 1, windowedMagnificationAreas.size());
+ assertEquals(windowedMagnificationAreas.get(0).mSurfaceControl, windowingLayer);
+ } else {
+ assertNotEquals(mDisplayContent.mSurfaceControl, windowingLayer);
+ }
+ }
+
+ @Test
public void testFindScrollCaptureTargetWindow_behindWindow() {
DisplayContent display = createNewDisplay();
Task stack = createTaskStackOnDisplay(display);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
index 7c4f7db..33e8fc0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
@@ -312,8 +312,7 @@
private String getStoredDisplayAttributeValue(TestStorage storage, String attr)
throws Exception {
try (InputStream stream = storage.openRead()) {
- TypedXmlPullParser parser = Xml.newFastPullParser();
- parser.setInput(stream, StandardCharsets.UTF_8.name());
+ TypedXmlPullParser parser = Xml.resolvePullParser(stream);
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG
&& type != XmlPullParser.END_DOCUMENT) {
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 ecbfac8..eff6919 100644
--- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
+++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
@@ -136,6 +136,11 @@
}
@Override
+ public SurfaceControl.Transaction setBackgroundBlurRadius(SurfaceControl sc, int radius) {
+ return this;
+ }
+
+ @Override
public SurfaceControl.Transaction setLayerStack(SurfaceControl sc, int layerStack) {
return this;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
index b78d6bb..001afe3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
@@ -116,10 +116,6 @@
}
@Override
- public void dispatchPointerCaptureChanged(boolean hasCapture) {
- }
-
- @Override
public void requestScrollCapture(IScrollCaptureCallbacks callbacks) throws RemoteException {
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 6b9993a..b7101c8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -74,13 +74,12 @@
import android.view.SurfaceControl;
import android.window.ITaskOrganizer;
import android.window.IWindowContainerTransactionCallback;
+import android.window.StartingWindowInfo;
import android.window.TaskAppearedInfo;
import android.window.WindowContainerTransaction;
import androidx.test.filters.SmallTest;
-import com.android.server.wm.TaskOrganizerController.PendingTaskEvent;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -151,14 +150,10 @@
final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack);
- // Ensure events dispatch to organizer.
- mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
stack.removeImmediately();
- // Ensure events dispatch to organizer.
- mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer).onTaskVanished(any());
}
@@ -167,21 +162,15 @@
final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack, false);
- // Ensure events dispatch to organizer.
- mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, never())
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
stack.setHasBeenVisible(true);
- // Ensure events dispatch to organizer.
- mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
assertTrue(stack.getHasBeenVisible());
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
stack.removeImmediately();
- // Ensure events dispatch to organizer.
- mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer).onTaskVanished(any());
}
@@ -206,16 +195,12 @@
final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack, false /* fakeDraw */);
- // Ensure events dispatch to organizer.
- mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, never())
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
assertTrue(stack.isOrganized());
mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer);
- // Ensure events dispatch to organizer.
- mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
assertTaskVanished(organizer, false /* expectVanished */, stack);
assertFalse(stack.isOrganized());
}
@@ -225,16 +210,11 @@
final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack);
- // Ensure events dispatch to organizer.
- mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
assertTrue(stack.isOrganized());
stack.setTaskOrganizer(null);
- // Ensure events dispatch to organizer.
- mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
-
verify(organizer).onTaskVanished(any());
assertFalse(stack.isOrganized());
}
@@ -244,16 +224,11 @@
final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack);
- // Ensure events dispatch to organizer.
- mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
assertTrue(stack.isOrganized());
mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer);
- // Ensure events dispatch to organizer.
- mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
-
assertTaskVanished(organizer, true /* expectVanished */, stack);
assertFalse(stack.isOrganized());
}
@@ -268,8 +243,6 @@
final Task task3 = createTask(stack3);
final ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>();
final ITaskOrganizer organizer = registerMockOrganizer(existingTasks);
- // Ensure events dispatch to organizer.
- mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
// verify that tasks are returned and taskAppeared is not called
assertContainsTasks(existingTasks, stack, stack2, stack3);
@@ -281,8 +254,6 @@
// Now we replace the registration and verify the new organizer receives existing tasks
final ArrayList<TaskAppearedInfo> existingTasks2 = new ArrayList<>();
final ITaskOrganizer organizer2 = registerMockOrganizer(existingTasks2);
- // Ensure events dispatch to organizer.
- mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
assertContainsTasks(existingTasks2, stack, stack2, stack3);
verify(organizer2, times(0)).onTaskAppeared(any(RunningTaskInfo.class),
any(SurfaceControl.class));
@@ -294,8 +265,6 @@
// Now we unregister the second one, the first one should automatically be reregistered
// so we verify that it's now seeing changes.
mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer2);
- // Ensure events dispatch to organizer.
- mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, times(3))
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
assertTaskVanished(organizer2, true /* expectVanished */, stack, stack2, stack3);
@@ -538,12 +507,12 @@
public void testTileAddRemoveChild() {
ITaskOrganizer listener = new ITaskOrganizer.Stub() {
@Override
- public void addStartingWindow(ActivityManager.RunningTaskInfo info, IBinder appToken) {
+ public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
}
@Override
- public void removeStartingWindow(ActivityManager.RunningTaskInfo info) { }
+ public void removeStartingWindow(int taskId) { }
@Override
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { }
@@ -603,12 +572,12 @@
final boolean[] called = {false};
ITaskOrganizer listener = new ITaskOrganizer.Stub() {
@Override
- public void addStartingWindow(ActivityManager.RunningTaskInfo info, IBinder appToken) {
+ public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
}
@Override
- public void removeStartingWindow(ActivityManager.RunningTaskInfo info) { }
+ public void removeStartingWindow(int taskId) { }
@Override
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { }
@@ -674,12 +643,12 @@
final ArrayMap<IBinder, RunningTaskInfo> lastReportedTiles = new ArrayMap<>();
ITaskOrganizer listener = new ITaskOrganizer.Stub() {
@Override
- public void addStartingWindow(ActivityManager.RunningTaskInfo info, IBinder appToken) {
+ public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
}
@Override
- public void removeStartingWindow(ActivityManager.RunningTaskInfo info) { }
+ public void removeStartingWindow(int taskId) { }
@Override
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { }
@@ -818,9 +787,9 @@
RunningTaskInfo mInfo;
@Override
- public void addStartingWindow(ActivityManager.RunningTaskInfo info, IBinder appToken) { }
+ public void addStartingWindow(StartingWindowInfo info, IBinder appToken) { }
@Override
- public void removeStartingWindow(ActivityManager.RunningTaskInfo info) { }
+ public void removeStartingWindow(int taskId) { }
@Override
public void onTaskAppeared(RunningTaskInfo info, SurfaceControl leash) {
mInfo = info;
@@ -887,8 +856,6 @@
.setAspectRatio(new Rational(3, 4)).build();
mWm.mAtmService.mActivityClientController.setPictureInPictureParams(record.token, p2);
waitUntilHandlersIdle();
- // Ensure events dispatch to organizer.
- mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
assertNotNull(o.mChangedInfo);
assertNotNull(o.mChangedInfo.pictureInPictureParams);
final Rational ratio = o.mChangedInfo.pictureInPictureParams.getAspectRatioRational();
@@ -928,24 +895,16 @@
stack.setTaskOrganizer(organizer);
// setHasBeenVisible was already called once by the set-up code.
stack.setHasBeenVisible(true);
- // Ensure events dispatch to organizer.
- mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, times(1))
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
stack.setTaskOrganizer(null);
- // Ensure events dispatch to organizer.
- mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, times(1)).onTaskVanished(any());
stack.setTaskOrganizer(organizer);
- // Ensure events dispatch to organizer.
- mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, times(2))
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
stack.removeImmediately();
- // Ensure events dispatch to organizer.
- mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, times(2)).onTaskVanished(any());
}
@@ -964,8 +923,6 @@
// Verify a back pressed does not call the organizer
mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(activity.token);
- // Ensure events dispatch to organizer.
- mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, never()).onBackPressedOnTaskRoot(any());
// Enable intercepting back
@@ -974,8 +931,6 @@
// Verify now that the back press does call the organizer
mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(activity.token);
- // Ensure events dispatch to organizer.
- mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, times(1)).onBackPressedOnTaskRoot(any());
// Disable intercepting back
@@ -984,8 +939,6 @@
// Verify now that the back press no longer calls the organizer
mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(activity.token);
- // Ensure events dispatch to organizer.
- mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, times(1)).onBackPressedOnTaskRoot(any());
}
@@ -1066,151 +1019,6 @@
assertTrue(task2.isOrganized());
}
- @Test
- public void testAppearDeferThenInfoChange() {
- final ITaskOrganizer organizer = registerMockOrganizer();
- final Task stack = createStack();
-
- // Assume layout defer
- mWm.mWindowPlacerLocked.deferLayout();
-
- final Task task = createTask(stack);
- final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
-
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
- record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription"));
- waitUntilHandlersIdle();
-
- ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
- assertEquals(1, pendingEvents.size());
- assertEquals(PendingTaskEvent.EVENT_APPEARED, pendingEvents.get(0).mEventType);
- assertEquals("TestDescription",
- pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel());
- }
-
- @Test
- public void testAppearDeferThenVanish() {
- final ITaskOrganizer organizer = registerMockOrganizer();
- final Task stack = createStack();
-
- // Assume layout defer
- mWm.mWindowPlacerLocked.deferLayout();
-
- final Task task = createTask(stack);
-
- stack.removeImmediately();
- waitUntilHandlersIdle();
-
- ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
- assertEquals(0, pendingEvents.size());
- }
-
- @Test
- public void testInfoChangeDeferMultiple() {
- final ITaskOrganizer organizer = registerMockOrganizer();
- final Task stack = createStack();
- final Task task = createTask(stack);
- final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
-
- // Assume layout defer
- mWm.mWindowPlacerLocked.deferLayout();
-
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
- record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription"));
- waitUntilHandlersIdle();
-
- ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
- assertEquals(1, pendingEvents.size());
- assertEquals(PendingTaskEvent.EVENT_INFO_CHANGED, pendingEvents.get(0).mEventType);
- assertEquals("TestDescription",
- pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel());
-
- record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription2"));
- waitUntilHandlersIdle();
-
- pendingEvents = getTaskPendingEvent(stack);
- assertEquals(1, pendingEvents.size());
- assertEquals(PendingTaskEvent.EVENT_INFO_CHANGED, pendingEvents.get(0).mEventType);
- assertEquals("TestDescription2",
- pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel());
- }
-
- @Test
- public void testInfoChangDeferThenVanish() {
- final ITaskOrganizer organizer = registerMockOrganizer();
- final Task stack = createStack();
- final Task task = createTask(stack);
- final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
-
- // Assume layout defer
- mWm.mWindowPlacerLocked.deferLayout();
-
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
- record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription"));
-
- stack.removeImmediately();
- waitUntilHandlersIdle();
-
- ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
- assertEquals(1, pendingEvents.size());
- assertEquals(PendingTaskEvent.EVENT_VANISHED, pendingEvents.get(0).mEventType);
- assertEquals("TestDescription",
- pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel());
- }
-
- @Test
- public void testVanishDeferThenInfoChange() {
- final ITaskOrganizer organizer = registerMockOrganizer();
- final Task stack = createStack();
- final Task task = createTask(stack);
- final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
-
- // Assume layout defer
- mWm.mWindowPlacerLocked.deferLayout();
-
- stack.removeImmediately();
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
- waitUntilHandlersIdle();
-
- ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
- assertEquals(1, pendingEvents.size());
- assertEquals(PendingTaskEvent.EVENT_VANISHED, pendingEvents.get(0).mEventType);
- }
-
- @Test
- public void testVanishDeferThenBackOnRoot() {
- final ITaskOrganizer organizer = registerMockOrganizer();
- final Task stack = createStack();
- final Task task = createTask(stack);
- final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
-
- // Assume layout defer
- mWm.mWindowPlacerLocked.deferLayout();
-
- stack.removeImmediately();
- mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(record.token);
- waitUntilHandlersIdle();
-
- ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
- assertEquals(1, pendingEvents.size());
- assertEquals(PendingTaskEvent.EVENT_VANISHED, pendingEvents.get(0).mEventType);
- }
-
- private ArrayList<PendingTaskEvent> getTaskPendingEvent(Task task) {
- ArrayList<PendingTaskEvent> total =
- mWm.mAtmService.mTaskOrganizerController.getPendingEventList();
- ArrayList<PendingTaskEvent> result = new ArrayList();
-
- for (int i = 0; i < total.size(); i++) {
- PendingTaskEvent entry = total.get(i);
- if (entry.mTask.mTaskId == task.mTaskId) {
- result.add(entry);
- }
- }
-
- return result;
- }
-
/**
* Verifies that task vanished is called for a specific task.
*/
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 76f8207..592580a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -739,6 +739,12 @@
InputMonitor.setInputWindowInfoIfNeeded(transaction, sc, handleWrapper);
verify(transaction, never()).setInputWindowInfo(any(), any());
+ // The rotated bounds have higher priority as the touchable region.
+ final Rect rotatedBounds = new Rect(0, 0, 123, 456);
+ doReturn(rotatedBounds).when(win.mToken).getFixedRotationTransformDisplayBounds();
+ mDisplayContent.getInputMonitor().populateInputWindowHandle(handleWrapper, win);
+ assertEquals(rotatedBounds, handle.touchableRegion.getBounds());
+
// Populate as an overlay to disable the input of window.
InputMonitor.populateOverlayInputInfo(handleWrapper, false /* isVisible */);
// The overlay attributes should be set.
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index e13a595..0d31d38 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -84,6 +84,7 @@
import android.view.WindowManager;
import android.view.WindowManager.DisplayImePolicy;
import android.window.ITaskOrganizer;
+import android.window.StartingWindowInfo;
import com.android.internal.util.ArrayUtils;
import com.android.server.AttributeCache;
@@ -1090,10 +1091,10 @@
mMoveToSecondaryOnEnter = move;
}
@Override
- public void addStartingWindow(ActivityManager.RunningTaskInfo info, IBinder appToken) {
+ public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
}
@Override
- public void removeStartingWindow(ActivityManager.RunningTaskInfo info) {
+ public void removeStartingWindow(int taskId) {
}
@Override
public void onTaskAppeared(ActivityManager.RunningTaskInfo info, SurfaceControl leash) {
@@ -1121,9 +1122,9 @@
mService.mTaskOrganizerController.setLaunchRoot(mDisplayId,
mSecondary.mRemoteToken.toWindowContainerToken());
DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId);
- dc.forAllRootTasks(stack -> {
- if (!WindowConfiguration.isSplitScreenWindowingMode(stack.getWindowingMode())) {
- stack.reparent(mSecondary, POSITION_BOTTOM);
+ dc.forAllRootTasks(rootTask -> {
+ if (!WindowConfiguration.isSplitScreenWindowingMode(rootTask.getWindowingMode())) {
+ rootTask.reparent(mSecondary, POSITION_BOTTOM);
}
});
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index d645e86..56345c0 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2050,7 +2050,13 @@
* via {@link android.telecom.PhoneAccount#CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE}
* and can choose to hide or show the video calling icon based on whether a contact supports
* video.
+ *
+ * @deprecated No longer used in framework code, however it may still be used by applications
+ * that have not updated their code. This config should still be set to {@code true} if
+ * {@link Ims#KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL} is set to {@code true} and
+ * {@link Ims#KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL} is set to {@code true}.
*/
+ @Deprecated
public static final String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
/**
@@ -3866,13 +3872,51 @@
* <p>
* If this key's value is set to false, the procedure for RCS contact capability exchange
* via SIP SUBSCRIBE/NOTIFY will also be disabled internally, and
- * {@link #KEY_USE_RCS_PRESENCE_BOOL} must also be set to false to ensure apps do not
- * improperly think that capability exchange via SIP PUBLISH is enabled.
+ * {@link Ims#KEY_ENABLE_PRESENCE_PUBLISH_BOOL} must also be set to false to ensure
+ * apps do not improperly think that capability exchange via SIP PUBLISH is enabled.
* <p> The default value for this key is {@code false}.
*/
public static final String KEY_ENABLE_PRESENCE_PUBLISH_BOOL =
KEY_PREFIX + "enable_presence_publish_bool";
+ /**
+ * Flag indicating whether or not this carrier supports the exchange of phone numbers with
+ * the carrier's RCS presence server in order to retrieve the RCS capabilities of requested
+ * contacts used in the RCS User Capability Exchange (UCE) procedure. See RCC.71, section 3
+ * for more information.
+ * <p>
+ * When presence is supported, the device uses the SIP SUBSCRIBE/NOTIFY procedure internally
+ * to retrieve the requested RCS capabilities. See
+ * {@link android.telephony.ims.RcsUceAdapter} for more information on how RCS capabilities
+ * can be retrieved from the carrier's network.
+ */
+ public static final String KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL =
+ KEY_PREFIX + "enable_presence_capability_exchange_bool";
+
+
+ /**
+ * Flag indicating whether or not the carrier expects the RCS UCE service to periodically
+ * refresh the RCS capabilities cache of the user's contacts as well as request the
+ * capabilities of call contacts when the SIM card is first inserted or when a new contact
+ * is added, removed, or modified. This corresponds to the RCC.07 A.19
+ * "DISABLE INITIAL ADDRESS BOOK SCAN" parameter.
+ * <p>
+ * If this flag is disabled, the capabilities cache will not be refreshed internally at all
+ * and will only be updated if the cached capabilities are stale when an application
+ * requests them.
+ */
+ public static final String KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL =
+ KEY_PREFIX + "rcs_bulk_capability_exchange_bool";
+
+ /**
+ * Flag indicating whether or not the carrier supports capability exchange with a list of
+ * contacts. When {@code true}, the device will batch together multiple requests and
+ * construct a RLMI document in the SIP SUBSCRIBE request (see RFC 4662). If {@code false},
+ * the request will be split up into one SIP SUBSCRIBE request per contact.
+ */
+ public static final String KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL =
+ KEY_PREFIX + "enable_presence_group_subscribe_bool";
+
private Ims() {}
private static PersistableBundle getDefaults() {
@@ -3880,6 +3924,9 @@
defaults.putInt(KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT, 4000);
defaults.putBoolean(KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, false);
defaults.putBoolean(KEY_ENABLE_PRESENCE_PUBLISH_BOOL, false);
+ defaults.putBoolean(KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL, false);
+ defaults.putBoolean(KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL, false);
+ defaults.putBoolean(KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL, true);
return defaults;
}
}
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index d502da9..99a77ae5 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -915,6 +915,8 @@
public static final int IPV6_PREFIX_UNAVAILABLE = 0x8CA;
/** System preference change back to SRAT during handoff */
public static final int HANDOFF_PREFERENCE_CHANGED = 0x8CB;
+ /** Data call fail due to the slice not being allowed for the data call. */
+ public static final int SLICE_REJECTED = 0x8CC;
//IKE error notifications message as specified in 3GPP TS 24.302 (Section 8.1.2.2).
@@ -985,7 +987,7 @@
* the authentication failed.
*/
public static final int IWLAN_IKEV2_AUTH_FAILURE = 0x4001;
- /** IKE message timeout, tunnel setup failed due to no response from EPDG */
+ /** IKE message timeout, tunnel setup failed due to no response from EPDG */
public static final int IWLAN_IKEV2_MSG_TIMEOUT = 0x4002;
/** IKE Certification validation failure */
public static final int IWLAN_IKEV2_CERT_INVALID = 0x4003;
@@ -1419,6 +1421,7 @@
sFailCauseMap.put(VSNCP_RECONNECT_NOT_ALLOWED, "VSNCP_RECONNECT_NOT_ALLOWED");
sFailCauseMap.put(IPV6_PREFIX_UNAVAILABLE, "IPV6_PREFIX_UNAVAILABLE");
sFailCauseMap.put(HANDOFF_PREFERENCE_CHANGED, "HANDOFF_PREFERENCE_CHANGED");
+ sFailCauseMap.put(SLICE_REJECTED, "SLICE_REJECTED");
sFailCauseMap.put(IWLAN_PDN_CONNECTION_REJECTION, "IWLAN_PDN_CONNECTION_REJECTION");
sFailCauseMap.put(IWLAN_MAX_CONNECTION_REACHED, "IWLAN_MAX_CONNECTION_REACHED");
sFailCauseMap.put(IWLAN_SEMANTIC_ERROR_IN_THE_TFT_OPERATION,
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 31a1249..d4565f3 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -8671,6 +8671,77 @@
return Collections.EMPTY_LIST;
}
+ /**
+ * Call composer status OFF from user setting.
+ */
+ public static final int CALL_COMPOSER_STATUS_OFF = 0;
+
+ /**
+ * Call composer status ON from user setting.
+ */
+ public static final int CALL_COMPOSER_STATUS_ON = 1;
+
+ /** @hide */
+ @IntDef(prefix = {"CALL_COMPOSER_STATUS_"},
+ value = {
+ CALL_COMPOSER_STATUS_ON,
+ CALL_COMPOSER_STATUS_OFF,
+ })
+ public @interface CallComposerStatus {}
+
+ /**
+ * Set the user-set status for enriched calling with call composer.
+ *
+ * @param status user-set status for enriched calling with call composer;
+ * it must be a value of either {@link #CALL_COMPOSER_STATUS_ON}
+ * or {@link #CALL_COMPOSER_STATUS_OFF}.
+ *
+ * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
+ *
+ * @throws IllegalArgumentException if requested state is invalid.
+ * @throws SecurityException if the caller does not have the permission.
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void setCallComposerStatus(@CallComposerStatus int status) {
+ if (status != CALL_COMPOSER_STATUS_ON && status != CALL_COMPOSER_STATUS_OFF) {
+ throw new IllegalArgumentException("requested status is invalid");
+ }
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ telephony.setCallComposerStatus(getSubId(), status);
+ }
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Error calling ITelephony#setCallComposerStatus", ex);
+ ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get the user-set status for enriched calling with call composer.
+ *
+ * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
+ *
+ * @throws SecurityException if the caller does not have the permission.
+ *
+ * @return the user-set status for enriched calling with call composer either
+ * {@link #CALL_COMPOSER_STATUS_ON} or {@link #CALL_COMPOSER_STATUS_OFF}.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public @CallComposerStatus int getCallComposerStatus() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getCallComposerStatus(getSubId());
+ }
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Error calling ITelephony#getCallComposerStatus", ex);
+ ex.rethrowFromSystemServer();
+ }
+ return CALL_COMPOSER_STATUS_OFF;
+ }
/** @hide */
@SystemApi
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index 556f2d5..e217e9a 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -137,6 +137,7 @@
private final int mPduSessionId;
private final Qos mDefaultQos;
private final List<QosSession> mQosSessions;
+ private final SliceInfo mSliceInfo;
/**
* @param cause Data call fail cause. {@link DataFailCause#NONE} indicates no error.
@@ -187,6 +188,7 @@
mPduSessionId = PDU_SESSION_ID_NOT_SET;
mDefaultQos = null;
mQosSessions = new ArrayList<>();
+ mSliceInfo = null;
}
private DataCallResponse(@DataFailureCause int cause, long suggestedRetryTime, int id,
@@ -195,7 +197,8 @@
@Nullable List<InetAddress> dnsAddresses, @Nullable List<InetAddress> gatewayAddresses,
@Nullable List<InetAddress> pcscfAddresses, int mtu, int mtuV4, int mtuV6,
@HandoverFailureMode int handoverFailureMode, int pduSessionId,
- @Nullable Qos defaultQos, @Nullable List<QosSession> qosSessions) {
+ @Nullable Qos defaultQos, @Nullable List<QosSession> qosSessions,
+ @Nullable SliceInfo sliceInfo) {
mCause = cause;
mSuggestedRetryTime = suggestedRetryTime;
mId = id;
@@ -217,6 +220,7 @@
mPduSessionId = pduSessionId;
mDefaultQos = defaultQos;
mQosSessions = qosSessions;
+ mSliceInfo = sliceInfo;
}
/** @hide */
@@ -244,6 +248,7 @@
mDefaultQos = source.readParcelable(Qos.class.getClassLoader());
mQosSessions = new ArrayList<>();
source.readList(mQosSessions, QosSession.class.getClassLoader());
+ mSliceInfo = source.readParcelable(SliceInfo.class.getClassLoader());
}
/**
@@ -370,7 +375,7 @@
}
/**
- * @return default QOS of the data call received from the network
+ * @return default QOS of the data connection received from the network
*
* @hide
*/
@@ -381,16 +386,24 @@
}
/**
- * @return All the dedicated bearer QOS sessions of the data call received from the network
+ * @return All the dedicated bearer QOS sessions of the data connection received from the
+ * network.
*
* @hide
*/
-
@NonNull
public List<QosSession> getQosSessions() {
return mQosSessions;
}
+ /**
+ * @return The slice info related to this data connection.
+ */
+ @Nullable
+ public SliceInfo getSliceInfo() {
+ return mSliceInfo;
+ }
+
@NonNull
@Override
public String toString() {
@@ -413,6 +426,7 @@
.append(" pduSessionId=").append(getPduSessionId())
.append(" defaultQos=").append(mDefaultQos)
.append(" qosSessions=").append(mQosSessions)
+ .append(" sliceInfo=").append(mSliceInfo)
.append("}");
return sb.toString();
}
@@ -456,7 +470,8 @@
&& mHandoverFailureMode == other.mHandoverFailureMode
&& mPduSessionId == other.mPduSessionId
&& isQosSame
- && isQosSessionsSame;
+ && isQosSessionsSame
+ && Objects.equals(mSliceInfo, other.mSliceInfo);
}
@Override
@@ -464,7 +479,7 @@
return Objects.hash(mCause, mSuggestedRetryTime, mId, mLinkStatus, mProtocolType,
mInterfaceName, mAddresses, mDnsAddresses, mGatewayAddresses, mPcscfAddresses,
mMtu, mMtuV4, mMtuV6, mHandoverFailureMode, mPduSessionId, mDefaultQos,
- mQosSessions);
+ mQosSessions, mSliceInfo);
}
@Override
@@ -499,6 +514,7 @@
dest.writeParcelable(null, flags);
}
dest.writeList(mQosSessions);
+ dest.writeParcelable(mSliceInfo, flags);
}
public static final @android.annotation.NonNull Parcelable.Creator<DataCallResponse> CREATOR =
@@ -582,6 +598,8 @@
private List<QosSession> mQosSessions = new ArrayList<>();
+ private SliceInfo mSliceInfo;
+
/**
* Default constructor for Builder.
*/
@@ -805,6 +823,21 @@
}
/**
+ * The Slice used for this data connection.
+ * <p/>
+ * If a handover occurs from EPDG to 5G,
+ * this is the {@link SliceInfo} used in {@link DataService#setupDataCall}.
+ *
+ * @param sliceInfo the slice info for the data call
+ *
+ * @return The same instance of the builder.
+ */
+ public @NonNull Builder setSliceInfo(@Nullable SliceInfo sliceInfo) {
+ mSliceInfo = sliceInfo;
+ return this;
+ }
+
+ /**
* Build the DataCallResponse.
*
* @return the DataCallResponse object.
@@ -813,7 +846,7 @@
return new DataCallResponse(mCause, mSuggestedRetryTime, mId, mLinkStatus,
mProtocolType, mInterfaceName, mAddresses, mDnsAddresses, mGatewayAddresses,
mPcscfAddresses, mMtu, mMtuV4, mMtuV6, mHandoverFailureMode, mPduSessionId,
- mDefaultQos, mQosSessions);
+ mDefaultQos, mQosSessions, mSliceInfo);
}
}
}
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index 2ec9651..03c2ef9 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -194,13 +194,19 @@
* The standard range of values are 1-15 while 0 means no pdu session id
* was attached to this call. Reference: 3GPP TS 24.007 section
* 11.2.3.1b.
+ * @param sliceInfo used within the data connection when a handover occurs from EPDG to 5G.
+ * The value is null unless the access network is
+ * {@link android.telephony.AccessNetworkConstants.AccessNetworkType#NGRAN} and a
+ * handover is occurring from EPDG to 5G. If the slice passed is rejected, then
+ * {@link DataCallResponse#getCause()} is
+ * {@link android.telephony.DataFailCause#SLICE_REJECTED}.
* @param callback The result callback for this request.
*/
public void setupDataCall(int accessNetworkType, @NonNull DataProfile dataProfile,
boolean isRoaming, boolean allowRoaming,
@SetupDataReason int reason,
@Nullable LinkProperties linkProperties,
- @IntRange(from = 0, to = 15) int pduSessionId,
+ @IntRange(from = 0, to = 15) int pduSessionId, @Nullable SliceInfo sliceInfo,
@NonNull DataServiceCallback callback) {
/* Call the old version since the new version isn't supported */
setupDataCall(accessNetworkType, dataProfile, isRoaming, allowRoaming, reason,
@@ -392,10 +398,11 @@
public final int reason;
public final LinkProperties linkProperties;
public final int pduSessionId;
+ public final SliceInfo sliceInfo;
public final IDataServiceCallback callback;
SetupDataCallRequest(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
boolean allowRoaming, int reason, LinkProperties linkProperties,
- int pduSessionId, IDataServiceCallback callback) {
+ int pduSessionId, SliceInfo sliceInfo, IDataServiceCallback callback) {
this.accessNetworkType = accessNetworkType;
this.dataProfile = dataProfile;
this.isRoaming = isRoaming;
@@ -403,6 +410,7 @@
this.linkProperties = linkProperties;
this.reason = reason;
this.pduSessionId = pduSessionId;
+ this.sliceInfo = sliceInfo;
this.callback = callback;
}
}
@@ -513,6 +521,7 @@
setupDataCallRequest.dataProfile, setupDataCallRequest.isRoaming,
setupDataCallRequest.allowRoaming, setupDataCallRequest.reason,
setupDataCallRequest.linkProperties, setupDataCallRequest.pduSessionId,
+ setupDataCallRequest.sliceInfo,
(setupDataCallRequest.callback != null)
? new DataServiceCallback(setupDataCallRequest.callback)
: null);
@@ -676,10 +685,12 @@
@Override
public void setupDataCall(int slotIndex, int accessNetworkType, DataProfile dataProfile,
boolean isRoaming, boolean allowRoaming, int reason,
- LinkProperties linkProperties, int pduSessionId, IDataServiceCallback callback) {
+ LinkProperties linkProperties, int pduSessionId, SliceInfo sliceInfo,
+ IDataServiceCallback callback) {
mHandler.obtainMessage(DATA_SERVICE_REQUEST_SETUP_DATA_CALL, slotIndex, 0,
new SetupDataCallRequest(accessNetworkType, dataProfile, isRoaming,
- allowRoaming, reason, linkProperties, pduSessionId, callback))
+ allowRoaming, reason, linkProperties, pduSessionId, sliceInfo,
+ callback))
.sendToTarget();
}
diff --git a/telephony/java/android/telephony/data/IDataService.aidl b/telephony/java/android/telephony/data/IDataService.aidl
index 3f1f033..e0b9a1a 100644
--- a/telephony/java/android/telephony/data/IDataService.aidl
+++ b/telephony/java/android/telephony/data/IDataService.aidl
@@ -19,6 +19,7 @@
import android.net.LinkProperties;
import android.telephony.data.DataProfile;
import android.telephony.data.IDataServiceCallback;
+import android.telephony.data.SliceInfo;
/**
* {@hide}
@@ -29,7 +30,7 @@
void removeDataServiceProvider(int slotId);
void setupDataCall(int slotId, int accessNetwork, in DataProfile dataProfile, boolean isRoaming,
boolean allowRoaming, int reason, in LinkProperties linkProperties,
- int pduSessionId, IDataServiceCallback callback);
+ int pduSessionId, in SliceInfo sliceInfo, IDataServiceCallback callback);
void deactivateDataCall(int slotId, int cid, int reason, IDataServiceCallback callback);
void setInitialAttachApn(int slotId, in DataProfile dataProfile, boolean isRoaming,
IDataServiceCallback callback);
diff --git a/telephony/java/android/telephony/data/SliceInfo.aidl b/telephony/java/android/telephony/data/SliceInfo.aidl
new file mode 100644
index 0000000..286ea5e
--- /dev/null
+++ b/telephony/java/android/telephony/data/SliceInfo.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** @hide */
+package android.telephony.data;
+
+parcelable SliceInfo;
diff --git a/telephony/java/android/telephony/data/SliceInfo.java b/telephony/java/android/telephony/data/SliceInfo.java
new file mode 100644
index 0000000..51857a7
--- /dev/null
+++ b/telephony/java/android/telephony/data/SliceInfo.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.data;
+
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Represents a S-NSSAI as defined in 3GPP TS 24.501.
+ *
+ * @hide
+ */
+@SystemApi
+public final class SliceInfo implements Parcelable {
+ /**
+ * When set on a Slice Differentiator, this value indicates that there is no corresponding
+ * Slice.
+ */
+ public static final int SLICE_DIFFERENTIATOR_NO_SLICE = -1;
+
+ /**
+ * Indicates that the service type is not present.
+ */
+ public static final int SLICE_SERVICE_TYPE_NONE = 0;
+
+ /**
+ * Slice suitable for the handling of 5G enhanced Mobile Broadband.
+ */
+ public static final int SLICE_SERVICE_TYPE_EMBB = 1;
+
+ /**
+ * Slice suitable for the handling of ultra-reliable low latency communications.
+ */
+ public static final int SLICE_SERVICE_TYPE_URLLC = 2;
+
+ /**
+ * Slice suitable for the handling of massive IoT.
+ */
+ public static final int SLICE_SERVICE_TYPE_MIOT = 3;
+
+ /**
+ * The min acceptable value for a Slice Differentiator
+ */
+ @SuppressLint("MinMaxConstant")
+ public static final int MIN_SLICE_DIFFERENTIATOR = -1;
+
+ /**
+ * The max acceptable value for a Slice Differentiator
+ */
+ @SuppressLint("MinMaxConstant")
+ public static final int MAX_SLICE_DIFFERENTIATOR = 0xFFFFFE;
+
+ /** @hide */
+ @IntDef(prefix = { "SLICE_SERVICE_TYPE_" }, value = {
+ SLICE_SERVICE_TYPE_NONE,
+ SLICE_SERVICE_TYPE_EMBB,
+ SLICE_SERVICE_TYPE_URLLC,
+ SLICE_SERVICE_TYPE_MIOT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SliceServiceType {}
+
+
+ @SliceServiceType
+ private final int mSliceServiceType;
+ @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+ private final int mSliceDifferentiator;
+ @SliceServiceType
+ private final int mMappedHplmnSliceServiceType;
+ @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+ private final int mMappedHplmnSliceDifferentiator;
+
+ private SliceInfo(@SliceServiceType int sliceServiceType,
+ int sliceDifferentiator, int mappedHplmnSliceServiceType,
+ int mappedHplmnSliceDifferentiator) {
+ mSliceServiceType = sliceServiceType;
+ mSliceDifferentiator = sliceDifferentiator;
+ mMappedHplmnSliceDifferentiator = mappedHplmnSliceDifferentiator;
+ mMappedHplmnSliceServiceType = mappedHplmnSliceServiceType;
+ }
+
+ /**
+ * The type of service provided by the slice.
+ * <p/>
+ * see: 3GPP TS 24.501 Section 9.11.2.8.
+ */
+ @SliceServiceType
+ public int getSliceServiceType() {
+ return mSliceServiceType;
+ }
+
+ /**
+ * Identifies the slice from others with the same Slice Service Type.
+ * <p/>
+ * Returns {@link #SLICE_DIFFERENTIATOR_NO_SLICE} if {@link #getSliceServiceType} returns
+ * {@link #SLICE_SERVICE_TYPE_NONE}.
+ * <p/>
+ * see: 3GPP TS 24.501 Section 9.11.2.8.
+ */
+ @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+ public int getSliceDifferentiator() {
+ return mSliceDifferentiator;
+ }
+
+ /**
+ * Corresponds to a Slice Info (S-NSSAI) of the HPLMN.
+ * <p/>
+ * see: 3GPP TS 24.501 Section 9.11.2.8.
+ */
+ @SliceServiceType
+ public int getMappedHplmnSliceServiceType() {
+ return mMappedHplmnSliceServiceType;
+ }
+
+ /**
+ * This Slice Differentiator corresponds to a {@link SliceInfo} (S-NSSAI) of the HPLMN;
+ * {@link #getSliceDifferentiator()} is mapped to this value.
+ * <p/>
+ * Returns {@link #SLICE_DIFFERENTIATOR_NO_SLICE} if either of the following are true:
+ * <ul>
+ * <li>{@link #getSliceDifferentiator()} returns {@link #SLICE_DIFFERENTIATOR_NO_SLICE}</li>
+ * <li>{@link #getMappedHplmnSliceServiceType()} returns {@link #SLICE_SERVICE_TYPE_NONE}</li>
+ * </ul>
+ * <p/>
+ * see: 3GPP TS 24.501 Section 9.11.2.8.
+ */
+ @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+ public int getMappedHplmnSliceDifferentiator() {
+ return mMappedHplmnSliceDifferentiator;
+ }
+
+ private SliceInfo(@NonNull Parcel in) {
+ mSliceServiceType = in.readInt();
+ mSliceDifferentiator = in.readInt();
+ mMappedHplmnSliceServiceType = in.readInt();
+ mMappedHplmnSliceDifferentiator = in.readInt();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mSliceServiceType);
+ dest.writeInt(mSliceDifferentiator);
+ dest.writeInt(mMappedHplmnSliceServiceType);
+ dest.writeInt(mMappedHplmnSliceDifferentiator);
+ }
+
+ public static final @android.annotation.NonNull Parcelable.Creator<SliceInfo> CREATOR =
+ new Parcelable.Creator<SliceInfo>() {
+ @Override
+ @NonNull
+ public SliceInfo createFromParcel(@NonNull Parcel source) {
+ return new SliceInfo(source);
+ }
+
+ @Override
+ @NonNull
+ public SliceInfo[] newArray(int size) {
+ return new SliceInfo[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ return "SliceInfo{"
+ + "mSliceServiceType=" + sliceServiceTypeToString(mSliceServiceType)
+ + ", mSliceDifferentiator=" + mSliceDifferentiator
+ + ", mMappedHplmnSliceServiceType="
+ + sliceServiceTypeToString(mMappedHplmnSliceServiceType)
+ + ", mMappedHplmnSliceDifferentiator=" + mMappedHplmnSliceDifferentiator
+ + '}';
+ }
+
+ private static String sliceServiceTypeToString(@SliceServiceType int sliceServiceType) {
+ switch(sliceServiceType) {
+ case SLICE_SERVICE_TYPE_NONE:
+ return "NONE";
+ case SLICE_SERVICE_TYPE_EMBB:
+ return "EMBB";
+ case SLICE_SERVICE_TYPE_URLLC:
+ return "URLLC";
+ case SLICE_SERVICE_TYPE_MIOT:
+ return "MIOT";
+ default:
+ return Integer.toString(sliceServiceType);
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ SliceInfo sliceInfo = (SliceInfo) o;
+ return mSliceServiceType == sliceInfo.mSliceServiceType
+ && mSliceDifferentiator == sliceInfo.mSliceDifferentiator
+ && mMappedHplmnSliceServiceType == sliceInfo.mMappedHplmnSliceServiceType
+ && mMappedHplmnSliceDifferentiator == sliceInfo.mMappedHplmnSliceDifferentiator;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mSliceServiceType, mSliceDifferentiator, mMappedHplmnSliceServiceType,
+ mMappedHplmnSliceDifferentiator);
+ }
+
+ /**
+ * Provides a convenient way to set the fields of a {@link SliceInfo} when creating a
+ * new instance.
+ *
+ * <p>The example below shows how you might create a new {@code SliceInfo}:
+ *
+ * <pre><code>
+ *
+ * SliceInfo response = new SliceInfo.Builder()
+ * .setSliceServiceType(SLICE_SERVICE_TYPE_URLLC)
+ * .build();
+ * </code></pre>
+ */
+ public static final class Builder {
+ @SliceServiceType
+ private int mSliceServiceType = SLICE_SERVICE_TYPE_NONE;
+ @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+ private int mSliceDifferentiator = SLICE_DIFFERENTIATOR_NO_SLICE;
+ @SliceServiceType
+ private int mMappedHplmnSliceServiceType = SLICE_SERVICE_TYPE_NONE;
+ @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+ private int mMappedHplmnSliceDifferentiator = SLICE_DIFFERENTIATOR_NO_SLICE;
+
+ /**
+ * Default constructor for Builder.
+ */
+ public Builder() {
+ }
+
+ /**
+ * Set the Slice Service Type.
+ *
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setSliceServiceType(@SliceServiceType int mSliceServiceType) {
+ this.mSliceServiceType = mSliceServiceType;
+ return this;
+ }
+
+ /**
+ * Set the Slice Differentiator.
+ * <p/>
+ * A value of {@link #SLICE_DIFFERENTIATOR_NO_SLICE} indicates that there is no
+ * corresponding Slice.
+ *
+ * @throws IllegalArgumentException if the parameter is not between
+ * {@link #MIN_SLICE_DIFFERENTIATOR} and {@link #MAX_SLICE_DIFFERENTIATOR}.
+ *
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setSliceDifferentiator(
+ @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+ int sliceDifferentiator) {
+ if (sliceDifferentiator < MIN_SLICE_DIFFERENTIATOR
+ || sliceDifferentiator > MAX_SLICE_DIFFERENTIATOR) {
+ throw new IllegalArgumentException("The slice diffentiator value is out of range");
+ }
+ this.mSliceDifferentiator = sliceDifferentiator;
+ return this;
+ }
+
+ /**
+ * Set the HPLMN Slice Service Type.
+ *
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setMappedHplmnSliceServiceType(
+ @SliceServiceType int mappedHplmnSliceServiceType) {
+ this.mMappedHplmnSliceServiceType = mappedHplmnSliceServiceType;
+ return this;
+ }
+
+ /**
+ * Set the HPLMN Slice Differentiator.
+ * <p/>
+ * A value of {@link #SLICE_DIFFERENTIATOR_NO_SLICE} indicates that there is no
+ * corresponding Slice of the HPLMN.
+ *
+ * @throws IllegalArgumentException if the parameter is not between
+ * {@link #MIN_SLICE_DIFFERENTIATOR} and {@link #MAX_SLICE_DIFFERENTIATOR}.
+ *
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setMappedHplmnSliceDifferentiator(
+ @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+ int mappedHplmnSliceDifferentiator) {
+ if (mappedHplmnSliceDifferentiator < MIN_SLICE_DIFFERENTIATOR
+ || mappedHplmnSliceDifferentiator > MAX_SLICE_DIFFERENTIATOR) {
+ throw new IllegalArgumentException("The slice diffentiator value is out of range");
+ }
+ this.mMappedHplmnSliceDifferentiator = mappedHplmnSliceDifferentiator;
+ return this;
+ }
+
+ /**
+ * Build the {@link SliceInfo}.
+ *
+ * @return the {@link SliceInfo} object.
+ */
+ @NonNull
+ public SliceInfo build() {
+ return new SliceInfo(this.mSliceServiceType, this.mSliceDifferentiator,
+ this.mMappedHplmnSliceServiceType, this.mMappedHplmnSliceDifferentiator);
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index 885ff9b..ad461c0 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -30,7 +30,6 @@
import android.provider.Settings;
import android.telephony.AccessNetworkConstants;
import android.telephony.BinderCacheManager;
-import android.telephony.CarrierConfigManager;
import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IImsRcsController;
@@ -62,9 +61,10 @@
* been enabled by the user can be queried using {@link RcsUceAdapter#isUceSettingEnabled()}.
* <p>
* This intent will always be handled by the system, however the application should only send
- * this Intent if the carrier supports RCS contact discovery, which can be queried using the key
- * {@link CarrierConfigManager#KEY_USE_RCS_PRESENCE_BOOL}. Otherwise, the RCS contact discovery
- * opt-in dialog will not be shown.
+ * this Intent if the carrier supports bulk RCS contact exchange, which will be true if either
+ * key {@link android.telephony.CarrierConfigManager.Ims#KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL}
+ * or {@link android.telephony.CarrierConfigManager#KEY_USE_RCS_PRESENCE_BOOL} is set to true.
+ * Otherwise, the RCS contact discovery opt-in dialog will not be shown.
* <p>
* Input: A mandatory {@link Settings#EXTRA_SUB_ID} extra containing the subscription that the
* setting will be be shown for.
@@ -396,6 +396,7 @@
* rather the subscription is capable of this service over IMS.
* @see #isAvailable(int)
* @see android.telephony.CarrierConfigManager#KEY_USE_RCS_PRESENCE_BOOL
+ * @see android.telephony.CarrierConfigManager.Ims#KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL
* @throws ImsException if the IMS service is not available when calling this method.
* See {@link ImsException#getCode()} for more information on the error codes.
* @hide
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index ff240a0..de4da38 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -128,6 +128,15 @@
*/
boolean isRadioOnForSubscriberWithFeature(int subId, String callingPackage, String callingFeatureId);
+ /**
+ * Set the user-set status for enriched calling with call composer.
+ */
+ void setCallComposerStatus(int subId, int status);
+
+ /**
+ * Get the user-set status for enriched calling with call composer.
+ */
+ int getCallComposerStatus(int subId);
/**
* Supply a pin to unlock the SIM for particular subId.
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index cf3b03c..f7cebd1 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -817,6 +817,11 @@
}
@Override
+ public @NonNull Context createWindowContext(Display display, int type, Bundle options) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public boolean isRestricted() {
throw new UnsupportedOperationException();
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index bd7e8d7..e4db55e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -80,16 +80,39 @@
}
}
-fun WmAssertion.windowAlwaysVisible(
+fun WmAssertion.wallpaperWindowBecomesInvisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("wallpaperWindowBecomesInvisible", bugId, enabled) {
+ this.showsBelowAppWindow("Wallpaper")
+ .then()
+ .hidesBelowAppWindow("Wallpaper")
+ }
+}
+
+fun WmAssertion.appWindowAlwaysVisibleOnTop(
packageName: String,
bugId: Int = 0,
enabled: Boolean = bugId == 0
) {
- all("windowAlwaysVisible", bugId, enabled) {
+ all("appWindowAlwaysVisibleOnTop", bugId, enabled) {
this.showsAppWindowOnTop(packageName)
}
}
+fun WmAssertion.appWindowBecomesVisible(
+ appName: String,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("appWindowBecomesVisible", bugId, enabled) {
+ this.hidesAppWindow(appName)
+ .then()
+ .showsAppWindow(appName)
+ }
+}
+
@JvmOverloads
fun LayersAssertion.noUncoveredRegions(
beginRotation: Int,
@@ -214,6 +237,18 @@
}
}
+fun LayersAssertion.appLayerReplacesWallpaperLayer(
+ appName: String,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("appLayerReplacesWallpaperLayer", bugId, enabled) {
+ this.showsLayer("Wallpaper")
+ .then()
+ .replaceVisibleLayer("Wallpaper", appName)
+ }
+}
+
fun LayersAssertion.wallpaperLayerReplacesAppLayer(
testApp: IAppHelper,
bugId: Int = 0,
@@ -236,6 +271,30 @@
}
}
+fun LayersAssertion.layerBecomesVisible(
+ packageName: String,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("layerBecomesVisible", bugId, enabled) {
+ this.hidesLayer(packageName)
+ .then()
+ .showsLayer(packageName)
+ }
+}
+
+fun LayersAssertion.layerBecomesInvisible(
+ packageName: String,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("layerBecomesInvisible", bugId, enabled) {
+ this.showsLayer(packageName)
+ .then()
+ .hidesLayer(packageName)
+ }
+}
+
fun EventLogAssertion.focusChanges(
vararg windows: String,
bugId: Int = 0,
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
index 5798624..aa34b5d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
@@ -65,6 +65,17 @@
}
}
+fun WmAssertion.imeWindowBecomesVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("imeWindowBecomesVisible", bugId, enabled) {
+ this.hidesNonAppWindow(IME_WINDOW_TITLE)
+ .then()
+ .showsNonAppWindow(IME_WINDOW_TITLE)
+ }
+}
+
fun WmAssertion.imeWindowBecomesInvisible(
bugId: Int = 0,
enabled: Boolean = bugId == 0
@@ -76,6 +87,18 @@
}
}
+fun WmAssertion.imeAppWindowBecomesVisible(
+ windowName: String,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("imeAppWindowBecomesVisible", bugId, enabled) {
+ this.hidesAppWindow(windowName)
+ .then()
+ .showsAppWindow(windowName)
+ }
+}
+
fun WmAssertion.imeAppWindowBecomesInvisible(
testApp: IAppHelper,
bugId: Int = 0,
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index 64a8f30..28a8bd3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -33,6 +33,8 @@
import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.appWindowAlwaysVisibleOnTop
+import com.android.server.wm.flicker.layerAlwaysVisible
import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
@@ -56,8 +58,6 @@
flickerSpec: Flicker
) : FlickerTestRunner(testName, flickerSpec) {
companion object {
- private const val IME_WINDOW_TITLE = "InputMethod"
-
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): List<Array<Any>> {
@@ -93,12 +93,8 @@
statusBarWindowIsAlwaysVisible()
visibleWindowsShownMoreThanOneConsecutiveEntry()
- all("imeWindowBecomesVisible") {
- this.skipUntilFirstAssertion()
- .hidesNonAppWindow(IME_WINDOW_TITLE)
- .then()
- .showsNonAppWindow(IME_WINDOW_TITLE)
- }
+ imeWindowBecomesVisible()
+ appWindowAlwaysVisibleOnTop(testApp.`package`)
}
layersTrace {
@@ -110,6 +106,7 @@
visibleLayersShownMoreThanOneConsecutiveEntry()
imeLayerBecomesVisible()
+ layerAlwaysVisible(testApp.`package`)
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index 7bd96f5..c7114da 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -23,14 +23,27 @@
import com.android.server.wm.flicker.Flicker
import com.android.server.wm.flicker.FlickerTestRunner
import com.android.server.wm.flicker.FlickerTestRunnerFactory
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.helpers.hasWindow
+import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
+import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import com.android.server.wm.flicker.noUncoveredRegions
import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.testapp.ActivityOptions
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -54,8 +67,9 @@
fun getParams(): List<Array<Any>> {
val instrumentation = InstrumentationRegistry.getInstrumentation()
val testApp = ImeAppAutoFocusHelper(instrumentation)
+ val testAppComponentName = ActivityOptions.IME_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME
- return FlickerTestRunnerFactory(instrumentation, repetitions = 10)
+ return FlickerTestRunnerFactory(instrumentation, repetitions = 5)
.buildTest { configuration ->
withTestName { buildTestTag("reOpenImeAutoFocus", testApp, configuration) }
repeat { configuration.repetitions }
@@ -73,7 +87,7 @@
}
transitions {
device.reopenAppFromOverview()
- device.hasWindow(testApp.getPackage())
+ WindowManagerStateHelper().waitForFullScreenApp(testAppComponentName)
}
teardown {
eachRun {
@@ -84,6 +98,35 @@
this.setRotation(Surface.ROTATION_0)
}
}
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+ imeWindowBecomesVisible()
+ imeAppWindowBecomesVisible(testAppComponentName.className)
+ wallpaperWindowBecomesInvisible()
+ }
+
+ layersTrace {
+ noUncoveredRegions(Surface.ROTATION_0, configuration.endRotation,
+ bugId = 141361128)
+ navBarLayerRotatesAndScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ statusBarLayerRotatesScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ statusBarLayerIsAlwaysVisible(
+ enabled = Surface.ROTATION_0 == configuration.endRotation)
+ navBarLayerIsAlwaysVisible(
+ enabled = Surface.ROTATION_0 == configuration.endRotation)
+ visibleLayersShownMoreThanOneConsecutiveEntry(
+ enabled = Surface.ROTATION_0 == configuration.endRotation)
+
+ imeLayerBecomesVisible()
+ appLayerReplacesWallpaperLayer(testAppComponentName.className)
+ }
+ }
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
index 72efdb1..71920f6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
@@ -17,20 +17,8 @@
package com.android.server.wm.flicker.launch
import android.platform.helpers.IAppHelper
-import com.android.server.wm.flicker.dsl.LayersAssertion
import com.android.server.wm.flicker.dsl.WmAssertion
-fun WmAssertion.wallpaperWindowBecomesInvisible(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("wallpaperWindowBecomesInvisible", bugId, enabled) {
- this.showsBelowAppWindow("Wallpaper")
- .then()
- .hidesBelowAppWindow("Wallpaper")
- }
-}
-
fun WmAssertion.appWindowReplacesLauncherAsTopWindow(
testApp: IAppHelper,
bugId: Int = 0,
@@ -41,16 +29,4 @@
.then()
.showsAppWindowOnTop("Snapshot", testApp.getPackage())
}
-}
-
-fun LayersAssertion.appLayerReplacesWallpaperLayer(
- testApp: IAppHelper,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("appLayerReplacesWallpaperLayer", bugId, enabled) {
- this.showsLayer("Wallpaper")
- .then()
- .replaceVisibleLayer("Wallpaper", testApp.getPackage())
- }
}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 686ddcb..d81c24d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -40,6 +40,8 @@
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
+import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -107,7 +109,7 @@
statusBarLayerIsAlwaysVisible(enabled = false)
visibleLayersShownMoreThanOneConsecutiveEntry(bugId = 174541970)
- appLayerReplacesWallpaperLayer(testApp)
+ appLayerReplacesWallpaperLayer(testApp.`package`)
}
eventLog {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 5aef314..1b682c0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -29,7 +29,6 @@
import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.helpers.StandardAppHelper
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.helpers.hasWindow
import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
@@ -42,6 +41,10 @@
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
+import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -83,7 +86,9 @@
}
transitions {
device.reopenAppFromOverview()
- device.hasWindow(testApp.getPackage())
+ WindowManagerStateHelper().waitForFullScreenApp(
+ ActivityOptions.SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME
+ )
}
teardown {
test {
@@ -115,7 +120,7 @@
visibleLayersShownMoreThanOneConsecutiveEntry(
enabled = Surface.ROTATION_0 == configuration.endRotation)
- appLayerReplacesWallpaperLayer(testApp)
+ appLayerReplacesWallpaperLayer(testApp.`package`)
}
eventLog {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 9b4223a..3703d9c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -40,6 +40,8 @@
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
+import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -112,7 +114,7 @@
visibleLayersShownMoreThanOneConsecutiveEntry(
enabled = Surface.ROTATION_0 == configuration.endRotation)
- appLayerReplacesWallpaperLayer(testApp)
+ appLayerReplacesWallpaperLayer(testApp.`package`)
}
eventLog {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index a1a7102..120354b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -30,7 +30,7 @@
import com.android.server.wm.flicker.FlickerTestRunnerFactory
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.focusDoesNotChange
-import com.android.server.wm.flicker.windowAlwaysVisible
+import com.android.server.wm.flicker.appWindowAlwaysVisibleOnTop
import com.android.server.wm.flicker.layerAlwaysVisible
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.buildTestTag
@@ -146,7 +146,7 @@
navBarWindowIsAlwaysVisible(bugId = 140855415)
statusBarWindowIsAlwaysVisible(bugId = 140855415)
visibleWindowsShownMoreThanOneConsecutiveEntry()
- windowAlwaysVisible(configuration.intentPackageName)
+ appWindowAlwaysVisibleOnTop(configuration.intentPackageName)
}
layersTrace {
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 1899411..f167e95 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -23,4 +23,10 @@
public static final ComponentName SEAMLESS_ACTIVITY_COMPONENT_NAME =
new ComponentName("com.android.server.wm.flicker.testapp",
"com.android.server.wm.flicker.testapp.SeamlessRotationActivity");
+ public static final ComponentName IME_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME =
+ new ComponentName("com.android.server.wm.flicker.testapp",
+ "com.android.server.wm.flicker.testapp.ImeActivityAutoFocus");
+ public static final ComponentName SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME =
+ new ComponentName("com.android.server.wm.flicker.testapp",
+ "com.android.server.wm.flicker.testapp.SimpleActivity");
}
diff --git a/tests/net/common/java/android/net/NetworkProviderTest.kt b/tests/net/common/java/android/net/NetworkProviderTest.kt
index 77e9f12..bcc9072 100644
--- a/tests/net/common/java/android/net/NetworkProviderTest.kt
+++ b/tests/net/common/java/android/net/NetworkProviderTest.kt
@@ -29,6 +29,7 @@
import com.android.net.module.util.ArrayTrackRecord
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
+import com.android.testutils.isDevSdkInRange
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -173,10 +174,12 @@
@Test
fun testDeclareNetworkRequestUnfulfillable() {
val mockContext = mock(Context::class.java)
- val provider = createNetworkProvider(mockContext)
- // ConnectivityManager not required at creation time
- verifyNoMoreInteractions(mockContext)
doReturn(mCm).`when`(mockContext).getSystemService(Context.CONNECTIVITY_SERVICE)
+ val provider = createNetworkProvider(mockContext)
+ // ConnectivityManager not required at creation time after R
+ if (!isDevSdkInRange(0, Build.VERSION_CODES.R)) {
+ verifyNoMoreInteractions(mockContext)
+ }
mCm.registerNetworkProvider(provider)
diff --git a/tests/net/java/android/net/NetworkUtilsTest.java b/tests/net/java/android/net/NetworkUtilsTest.java
index 3158cc8..7748288 100644
--- a/tests/net/java/android/net/NetworkUtilsTest.java
+++ b/tests/net/java/android/net/NetworkUtilsTest.java
@@ -16,24 +16,10 @@
package android.net;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-import static android.system.OsConstants.AF_UNIX;
-import static android.system.OsConstants.EPERM;
-import static android.system.OsConstants.SOCK_DGRAM;
-import static android.system.OsConstants.SOCK_STREAM;
-
import static junit.framework.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import android.system.ErrnoException;
-import android.system.Os;
-
import androidx.test.runner.AndroidJUnit4;
-import libcore.io.IoUtils;
-
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -139,50 +125,4 @@
assertEquals(BigInteger.valueOf(7l - 4 + 4 + 16 + 65536),
NetworkUtils.routedIPv6AddressCount(set));
}
-
- private static void expectSocketSuccess(String msg, int domain, int type) {
- try {
- IoUtils.closeQuietly(Os.socket(domain, type, 0));
- } catch (ErrnoException e) {
- fail(msg + e.getMessage());
- }
- }
-
- private static void expectSocketPemissionError(String msg, int domain, int type) {
- try {
- IoUtils.closeQuietly(Os.socket(domain, type, 0));
- fail(msg);
- } catch (ErrnoException e) {
- assertEquals(msg, e.errno, EPERM);
- }
- }
-
- private static void expectHasNetworking() {
- expectSocketSuccess("Creating a UNIX socket should not have thrown ErrnoException",
- AF_UNIX, SOCK_STREAM);
- expectSocketSuccess("Creating a AF_INET socket shouldn't have thrown ErrnoException",
- AF_INET, SOCK_DGRAM);
- expectSocketSuccess("Creating a AF_INET6 socket shouldn't have thrown ErrnoException",
- AF_INET6, SOCK_DGRAM);
- }
-
- private static void expectNoNetworking() {
- expectSocketSuccess("Creating a UNIX socket should not have thrown ErrnoException",
- AF_UNIX, SOCK_STREAM);
- expectSocketPemissionError(
- "Creating a AF_INET socket should have thrown ErrnoException(EPERM)",
- AF_INET, SOCK_DGRAM);
- expectSocketPemissionError(
- "Creating a AF_INET6 socket should have thrown ErrnoException(EPERM)",
- AF_INET6, SOCK_DGRAM);
- }
-
- @Test
- public void testSetAllowNetworkingForProcess() {
- expectHasNetworking();
- NetworkUtils.setAllowNetworkingForProcess(false);
- expectNoNetworking();
- NetworkUtils.setAllowNetworkingForProcess(true);
- expectHasNetworking();
- }
}
diff --git a/tests/net/java/com/android/internal/net/NetworkUtilsInternalTest.java b/tests/net/java/com/android/internal/net/NetworkUtilsInternalTest.java
new file mode 100644
index 0000000..3cfecd5
--- /dev/null
+++ b/tests/net/java/com/android/internal/net/NetworkUtilsInternalTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 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.net;
+
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.AF_UNIX;
+import static android.system.OsConstants.EPERM;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOCK_STREAM;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.junit.Assert.fail;
+
+import android.system.ErrnoException;
+import android.system.Os;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import libcore.io.IoUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@androidx.test.filters.SmallTest
+public class NetworkUtilsInternalTest {
+
+ private static void expectSocketSuccess(String msg, int domain, int type) {
+ try {
+ IoUtils.closeQuietly(Os.socket(domain, type, 0));
+ } catch (ErrnoException e) {
+ fail(msg + e.getMessage());
+ }
+ }
+
+ private static void expectSocketPemissionError(String msg, int domain, int type) {
+ try {
+ IoUtils.closeQuietly(Os.socket(domain, type, 0));
+ fail(msg);
+ } catch (ErrnoException e) {
+ assertEquals(msg, e.errno, EPERM);
+ }
+ }
+
+ private static void expectHasNetworking() {
+ expectSocketSuccess("Creating a UNIX socket should not have thrown ErrnoException",
+ AF_UNIX, SOCK_STREAM);
+ expectSocketSuccess("Creating a AF_INET socket shouldn't have thrown ErrnoException",
+ AF_INET, SOCK_DGRAM);
+ expectSocketSuccess("Creating a AF_INET6 socket shouldn't have thrown ErrnoException",
+ AF_INET6, SOCK_DGRAM);
+ }
+
+ private static void expectNoNetworking() {
+ expectSocketSuccess("Creating a UNIX socket should not have thrown ErrnoException",
+ AF_UNIX, SOCK_STREAM);
+ expectSocketPemissionError(
+ "Creating a AF_INET socket should have thrown ErrnoException(EPERM)",
+ AF_INET, SOCK_DGRAM);
+ expectSocketPemissionError(
+ "Creating a AF_INET6 socket should have thrown ErrnoException(EPERM)",
+ AF_INET6, SOCK_DGRAM);
+ }
+
+ @Test
+ public void testSetAllowNetworkingForProcess() {
+ expectHasNetworking();
+ NetworkUtilsInternal.setAllowNetworkingForProcess(false);
+ expectNoNetworking();
+ NetworkUtilsInternal.setAllowNetworkingForProcess(true);
+ expectHasNetworking();
+ }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 20b05b5..799b64e 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -8109,7 +8109,16 @@
@Test
public void testDumpDoesNotCrash() {
- StringWriter stringWriter = new StringWriter();
+ // Filing a couple requests prior to testing the dump.
+ final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
+ final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
+ final NetworkRequest genericRequest = new NetworkRequest.Builder()
+ .clearCapabilities().build();
+ final NetworkRequest wifiRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI).build();
+ mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
+ mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
+ final StringWriter stringWriter = new StringWriter();
mService.dump(new FileDescriptor(), new PrintWriter(stringWriter), new String[0]);
@@ -8131,11 +8140,11 @@
mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
- ConnectivityService.NetworkRequestInfo[] nriOutput = mService.requestsSortedById();
+ final ConnectivityService.NetworkRequestInfo[] nriOutput = mService.requestsSortedById();
assertTrue(nriOutput.length > 1);
for (int i = 0; i < nriOutput.length - 1; i++) {
- boolean isRequestIdInOrder =
+ final boolean isRequestIdInOrder =
nriOutput[i].mRequests.get(0).requestId
< nriOutput[i + 1].mRequests.get(0).requestId;
assertTrue(isRequestIdInOrder);
diff --git a/tests/net/java/com/android/server/NetworkManagementServiceTest.java b/tests/net/java/com/android/server/NetworkManagementServiceTest.java
index ea763d2..e150229 100644
--- a/tests/net/java/com/android/server/NetworkManagementServiceTest.java
+++ b/tests/net/java/com/android/server/NetworkManagementServiceTest.java
@@ -68,11 +68,12 @@
@SmallTest
public class NetworkManagementServiceTest {
private NetworkManagementService mNMService;
-
@Mock private Context mContext;
@Mock private IBatteryStats.Stub mBatteryStatsService;
@Mock private INetd.Stub mNetdService;
+ private static final int TEST_UID = 111;
+
@NonNull
@Captor
private ArgumentCaptor<INetdUnsolicitedEventListener> mUnsolListenerCaptor;
@@ -165,14 +166,14 @@
/**
* Interface class activity.
*/
- unsolListener.onInterfaceClassActivityChanged(true, 1, 1234, 0);
- expectSoon(observer).interfaceClassDataActivityChanged("1", true, 1234);
+ unsolListener.onInterfaceClassActivityChanged(true, 1, 1234, TEST_UID);
+ expectSoon(observer).interfaceClassDataActivityChanged("1", true, 1234, TEST_UID);
- unsolListener.onInterfaceClassActivityChanged(false, 9, 5678, 0);
- expectSoon(observer).interfaceClassDataActivityChanged("9", false, 5678);
+ unsolListener.onInterfaceClassActivityChanged(false, 9, 5678, TEST_UID);
+ expectSoon(observer).interfaceClassDataActivityChanged("9", false, 5678, TEST_UID);
- unsolListener.onInterfaceClassActivityChanged(false, 9, 4321, 0);
- expectSoon(observer).interfaceClassDataActivityChanged("9", false, 4321);
+ unsolListener.onInterfaceClassActivityChanged(false, 9, 4321, TEST_UID);
+ expectSoon(observer).interfaceClassDataActivityChanged("9", false, 4321, TEST_UID);
/**
* IP address changes.
@@ -222,8 +223,6 @@
assertFalse(mNMService.isFirewallEnabled());
}
- private static final int TEST_UID = 111;
-
@Test
public void testNetworkRestrictedDefault() {
assertFalse(mNMService.isNetworkRestricted(TEST_UID));
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
index fb0cfc0..89146f9 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
@@ -23,11 +23,11 @@
import static android.net.NetworkStats.UID_ALL;
import static android.net.NetworkStatsHistory.FIELD_ALL;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
-import static android.net.NetworkUtils.multiplySafeByRational;
import static android.os.Process.myUid;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational;
import static com.android.testutils.MiscAsserts.assertThrows;
import static org.junit.Assert.assertArrayEquals;
diff --git a/tests/vcn/java/android/net/vcn/VcnConfigTest.java b/tests/vcn/java/android/net/vcn/VcnConfigTest.java
new file mode 100644
index 0000000..77944de
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnConfigTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Collections;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnConfigTest {
+ private static final Set<VcnGatewayConnectionConfig> GATEWAY_CONNECTION_CONFIGS =
+ Collections.singleton(VcnGatewayConnectionConfigTest.buildTestConfig());
+
+ // Public visibility for VcnManagementServiceTest
+ public static VcnConfig buildTestConfig() {
+ VcnConfig.Builder builder = new VcnConfig.Builder();
+
+ for (VcnGatewayConnectionConfig gatewayConnectionConfig : GATEWAY_CONNECTION_CONFIGS) {
+ builder.addGatewayConnectionConfig(gatewayConnectionConfig);
+ }
+
+ return builder.build();
+ }
+
+ @Test
+ public void testBuilderRequiresGatewayConnectionConfig() {
+ try {
+ new VcnConfig.Builder().build();
+ fail("Expected exception due to no VcnGatewayConnectionConfigs provided");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ @Test
+ public void testBuilderAndGetters() {
+ final VcnConfig config = buildTestConfig();
+
+ assertEquals(GATEWAY_CONNECTION_CONFIGS, config.getGatewayConnectionConfigs());
+ }
+
+ @Test
+ public void testPersistableBundle() {
+ final VcnConfig config = buildTestConfig();
+
+ assertEquals(config, new VcnConfig(config.toPersistableBundle()));
+ }
+
+ @Test
+ public void testParceling() {
+ final VcnConfig config = buildTestConfig();
+
+ Parcel parcel = Parcel.obtain();
+ config.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ assertEquals(config, VcnConfig.CREATOR.createFromParcel(parcel));
+ }
+}
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
new file mode 100644
index 0000000..e98b6ef
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.net.NetworkCapabilities;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnGatewayConnectionConfigTest {
+ private static final int[] EXPOSED_CAPS =
+ new int[] {
+ NetworkCapabilities.NET_CAPABILITY_INTERNET, NetworkCapabilities.NET_CAPABILITY_MMS
+ };
+ private static final int[] UNDERLYING_CAPS = new int[] {NetworkCapabilities.NET_CAPABILITY_DUN};
+ private static final long[] RETRY_INTERVALS_MS =
+ new long[] {
+ TimeUnit.SECONDS.toMillis(5),
+ TimeUnit.SECONDS.toMillis(30),
+ TimeUnit.MINUTES.toMillis(1),
+ TimeUnit.MINUTES.toMillis(5),
+ TimeUnit.MINUTES.toMillis(15),
+ TimeUnit.MINUTES.toMillis(30)
+ };
+ private static final int MAX_MTU = 1360;
+
+ // Package protected for use in VcnConfigTest
+ static VcnGatewayConnectionConfig buildTestConfig() {
+ final VcnGatewayConnectionConfig.Builder builder =
+ new VcnGatewayConnectionConfig.Builder()
+ .setRetryInterval(RETRY_INTERVALS_MS)
+ .setMaxMtu(MAX_MTU);
+
+ for (int caps : EXPOSED_CAPS) {
+ builder.addExposedCapability(caps);
+ }
+
+ for (int caps : UNDERLYING_CAPS) {
+ builder.addRequiredUnderlyingCapability(caps);
+ }
+
+ return builder.build();
+ }
+
+ @Test
+ public void testBuilderRequiresNonEmptyExposedCaps() {
+ try {
+ new VcnGatewayConnectionConfig.Builder()
+ .addRequiredUnderlyingCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build();
+
+ fail("Expected exception due to invalid exposed capabilities");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ @Test
+ public void testBuilderRequiresNonEmptyUnderlyingCaps() {
+ try {
+ new VcnGatewayConnectionConfig.Builder()
+ .addExposedCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build();
+
+ fail("Expected exception due to invalid required underlying capabilities");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ @Test
+ public void testBuilderRequiresNonNullRetryInterval() {
+ try {
+ new VcnGatewayConnectionConfig.Builder().setRetryInterval(null);
+ fail("Expected exception due to invalid retryIntervalMs");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ @Test
+ public void testBuilderRequiresNonEmptyRetryInterval() {
+ try {
+ new VcnGatewayConnectionConfig.Builder().setRetryInterval(new long[0]);
+ fail("Expected exception due to invalid retryIntervalMs");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ @Test
+ public void testBuilderRequiresValidMtu() {
+ try {
+ new VcnGatewayConnectionConfig.Builder()
+ .setMaxMtu(VcnGatewayConnectionConfig.MIN_MTU_V6 - 1);
+ fail("Expected exception due to invalid mtu");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ @Test
+ public void testBuilderAndGetters() {
+ final VcnGatewayConnectionConfig config = buildTestConfig();
+
+ for (int cap : EXPOSED_CAPS) {
+ config.hasExposedCapability(cap);
+ }
+ for (int cap : UNDERLYING_CAPS) {
+ config.requiresUnderlyingCapability(cap);
+ }
+
+ assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMs());
+ assertEquals(MAX_MTU, config.getMaxMtu());
+ }
+
+ @Test
+ public void testPersistableBundle() {
+ final VcnGatewayConnectionConfig config = buildTestConfig();
+
+ assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle()));
+ }
+}
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index c91fdbf..1cc9532 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -16,42 +16,123 @@
package com.android.server;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.net.ConnectivityManager;
+import android.net.vcn.VcnConfig;
+import android.net.vcn.VcnConfigTest;
+import android.os.ParcelUuid;
+import android.os.PersistableBundle;
+import android.os.Process;
+import android.os.UserHandle;
import android.os.test.TestLooper;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.vcn.util.PersistableBundleUtils;
+
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.FileNotFoundException;
+import java.util.Collections;
+import java.util.Map;
+import java.util.UUID;
+
/** Tests for {@link VcnManagementService}. */
@RunWith(AndroidJUnit4.class)
@SmallTest
public class VcnManagementServiceTest {
+ private static final ParcelUuid TEST_UUID_1 = new ParcelUuid(new UUID(0, 0));
+ private static final ParcelUuid TEST_UUID_2 = new ParcelUuid(new UUID(1, 1));
+ private static final VcnConfig TEST_VCN_CONFIG = VcnConfigTest.buildTestConfig();
+ private static final Map<ParcelUuid, VcnConfig> TEST_VCN_CONFIG_MAP =
+ Collections.unmodifiableMap(Collections.singletonMap(TEST_UUID_1, TEST_VCN_CONFIG));
+
+ private static final SubscriptionInfo TEST_SUBSCRIPTION_INFO =
+ new SubscriptionInfo(
+ 1 /* id */,
+ "" /* iccId */,
+ 0 /* simSlotIndex */,
+ "Carrier" /* displayName */,
+ "Carrier" /* carrierName */,
+ 0 /* nameSource */,
+ 255 /* iconTint */,
+ "12345" /* number */,
+ 0 /* roaming */,
+ null /* icon */,
+ "0" /* mcc */,
+ "0" /* mnc */,
+ "0" /* countryIso */,
+ false /* isEmbedded */,
+ null /* nativeAccessRules */,
+ null /* cardString */,
+ false /* isOpportunistic */,
+ TEST_UUID_1.toString() /* groupUUID */,
+ 0 /* carrierId */,
+ 0 /* profileClass */);
+
private final Context mMockContext = mock(Context.class);
private final VcnManagementService.Dependencies mMockDeps =
mock(VcnManagementService.Dependencies.class);
private final TestLooper mTestLooper = new TestLooper();
private final ConnectivityManager mConnMgr = mock(ConnectivityManager.class);
+ private final TelephonyManager mTelMgr = mock(TelephonyManager.class);
+ private final SubscriptionManager mSubMgr = mock(SubscriptionManager.class);
private final VcnManagementService mVcnMgmtSvc;
+ private final PersistableBundleUtils.LockingReadWriteHelper mConfigReadWriteHelper =
+ mock(PersistableBundleUtils.LockingReadWriteHelper.class);
- public VcnManagementServiceTest() {
- doReturn(Context.CONNECTIVITY_SERVICE)
- .when(mMockContext)
- .getSystemServiceName(ConnectivityManager.class);
- doReturn(mConnMgr).when(mMockContext).getSystemService(Context.CONNECTIVITY_SERVICE);
+ public VcnManagementServiceTest() throws Exception {
+ setupSystemService(mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
+ setupSystemService(mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class);
+ setupSystemService(
+ mSubMgr, Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class);
doReturn(mTestLooper.getLooper()).when(mMockDeps).getLooper();
+ doReturn(Process.FIRST_APPLICATION_UID).when(mMockDeps).getBinderCallingUid();
+ doReturn(mConfigReadWriteHelper)
+ .when(mMockDeps)
+ .newPersistableBundleLockingReadWriteHelper(any());
+
+ final PersistableBundle bundle =
+ PersistableBundleUtils.fromMap(
+ TEST_VCN_CONFIG_MAP,
+ PersistableBundleUtils::fromParcelUuid,
+ VcnConfig::toPersistableBundle);
+ doReturn(bundle).when(mConfigReadWriteHelper).readFromDisk();
+
+ setupMockedCarrierPrivilege(true);
mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps);
}
+ private void setupSystemService(Object service, String name, Class<?> serviceClass) {
+ doReturn(name).when(mMockContext).getSystemServiceName(serviceClass);
+ doReturn(service).when(mMockContext).getSystemService(name);
+ }
+
+ private void setupMockedCarrierPrivilege(boolean isPrivileged) {
+ doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO))
+ .when(mSubMgr)
+ .getSubscriptionsInGroup(any());
+ doReturn(isPrivileged)
+ .when(mTelMgr)
+ .hasCarrierPrivileges(eq(TEST_SUBSCRIPTION_INFO.getSubscriptionId()));
+ }
+
@Test
public void testSystemReady() throws Exception {
mVcnMgmtSvc.systemReady();
@@ -59,4 +140,119 @@
verify(mConnMgr)
.registerNetworkProvider(any(VcnManagementService.VcnNetworkProvider.class));
}
+
+ @Test
+ public void testNonSystemServerRealConfigFileAccessPermission() throws Exception {
+ // Attempt to build a real instance of the dependencies, and verify we cannot write to the
+ // file.
+ VcnManagementService.Dependencies deps = new VcnManagementService.Dependencies();
+ PersistableBundleUtils.LockingReadWriteHelper configReadWriteHelper =
+ deps.newPersistableBundleLockingReadWriteHelper(
+ VcnManagementService.VCN_CONFIG_FILE);
+
+ // Even tests should not be able to read/write configs from disk; SELinux policies restrict
+ // it to only the system server.
+ // Reading config should always return null since the file "does not exist", and writing
+ // should throw an IOException.
+ assertNull(configReadWriteHelper.readFromDisk());
+
+ try {
+ configReadWriteHelper.writeToDisk(new PersistableBundle());
+ fail("Expected IOException due to SELinux policy");
+ } catch (FileNotFoundException expected) {
+ }
+ }
+
+ @Test
+ public void testLoadVcnConfigsOnStartup() throws Exception {
+ mTestLooper.dispatchAll();
+
+ assertEquals(TEST_VCN_CONFIG_MAP, mVcnMgmtSvc.getConfigs());
+ verify(mConfigReadWriteHelper).readFromDisk();
+ }
+
+ @Test
+ public void testSetVcnConfigRequiresNonSystemServer() throws Exception {
+ doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid();
+
+ try {
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, VcnConfigTest.buildTestConfig());
+ fail("Expected IllegalStateException exception for system server");
+ } catch (IllegalStateException expected) {
+ }
+ }
+
+ @Test
+ public void testSetVcnConfigRequiresSystemUser() throws Exception {
+ doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, Process.FIRST_APPLICATION_UID))
+ .when(mMockDeps)
+ .getBinderCallingUid();
+
+ try {
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, VcnConfigTest.buildTestConfig());
+ fail("Expected security exception for non system user");
+ } catch (SecurityException expected) {
+ }
+ }
+
+ @Test
+ public void testSetVcnConfigRequiresCarrierPrivileges() throws Exception {
+ setupMockedCarrierPrivilege(false);
+
+ try {
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, VcnConfigTest.buildTestConfig());
+ fail("Expected security exception for missing carrier privileges");
+ } catch (SecurityException expected) {
+ }
+ }
+
+ @Test
+ public void testSetVcnConfig() throws Exception {
+ // Use a different UUID to simulate a new VCN config.
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG);
+ assertEquals(TEST_VCN_CONFIG, mVcnMgmtSvc.getConfigs().get(TEST_UUID_2));
+ verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
+ }
+
+ @Test
+ public void testClearVcnConfigRequiresNonSystemServer() throws Exception {
+ doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid();
+
+ try {
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1);
+ fail("Expected IllegalStateException exception for system server");
+ } catch (IllegalStateException expected) {
+ }
+ }
+
+ @Test
+ public void testClearVcnConfigRequiresSystemUser() throws Exception {
+ doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, Process.FIRST_APPLICATION_UID))
+ .when(mMockDeps)
+ .getBinderCallingUid();
+
+ try {
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1);
+ fail("Expected security exception for non system user");
+ } catch (SecurityException expected) {
+ }
+ }
+
+ @Test
+ public void testClearVcnConfigRequiresCarrierPrivileges() throws Exception {
+ setupMockedCarrierPrivilege(false);
+
+ try {
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1);
+ fail("Expected security exception for missing carrier privileges");
+ } catch (SecurityException expected) {
+ }
+ }
+
+ @Test
+ public void testClearVcnConfig() throws Exception {
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1);
+ assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
+ verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
+ }
}
diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
new file mode 100644
index 0000000..17b8f64
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
+import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX;
+import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX;
+import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
+import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.ParcelUuid;
+import android.os.test.TestLooper;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
+import android.util.ArraySet;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+/** Tests for TelephonySubscriptionTracker */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class TelephonySubscriptionTrackerTest {
+ private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID());
+ private static final int TEST_SIM_SLOT_INDEX = 1;
+ private static final int TEST_SUBSCRIPTION_ID_1 = 2;
+ private static final SubscriptionInfo TEST_SUBINFO_1 = mock(SubscriptionInfo.class);
+ private static final int TEST_SUBSCRIPTION_ID_2 = 3;
+ private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class);
+ private static final Map<Integer, ParcelUuid> TEST_SUBID_TO_GROUP_MAP;
+
+ static {
+ final Map<Integer, ParcelUuid> subIdToGroupMap = new HashMap<>();
+ subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_PARCEL_UUID);
+ subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_2, TEST_PARCEL_UUID);
+ TEST_SUBID_TO_GROUP_MAP = Collections.unmodifiableMap(subIdToGroupMap);
+ }
+
+ @NonNull private final Context mContext;
+ @NonNull private final TestLooper mTestLooper;
+ @NonNull private final Handler mHandler;
+ @NonNull private final TelephonySubscriptionTracker.Dependencies mDeps;
+
+ @NonNull private final SubscriptionManager mSubscriptionManager;
+ @NonNull private final CarrierConfigManager mCarrierConfigManager;
+
+ @NonNull private TelephonySubscriptionTrackerCallback mCallback;
+ @NonNull private TelephonySubscriptionTracker mTelephonySubscriptionTracker;
+
+ public TelephonySubscriptionTrackerTest() {
+ mContext = mock(Context.class);
+ mTestLooper = new TestLooper();
+ mHandler = new Handler(mTestLooper.getLooper());
+ mDeps = mock(TelephonySubscriptionTracker.Dependencies.class);
+
+ mSubscriptionManager = mock(SubscriptionManager.class);
+ mCarrierConfigManager = mock(CarrierConfigManager.class);
+
+ doReturn(Context.TELEPHONY_SUBSCRIPTION_SERVICE)
+ .when(mContext)
+ .getSystemServiceName(SubscriptionManager.class);
+ doReturn(mSubscriptionManager)
+ .when(mContext)
+ .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+
+ doReturn(Context.CARRIER_CONFIG_SERVICE)
+ .when(mContext)
+ .getSystemServiceName(CarrierConfigManager.class);
+ doReturn(mCarrierConfigManager)
+ .when(mContext)
+ .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+
+ // subId 1, 2 are in same subGrp, only subId 1 is active
+ doReturn(TEST_PARCEL_UUID).when(TEST_SUBINFO_1).getGroupUuid();
+ doReturn(TEST_PARCEL_UUID).when(TEST_SUBINFO_2).getGroupUuid();
+ doReturn(TEST_SIM_SLOT_INDEX).when(TEST_SUBINFO_1).getSimSlotIndex();
+ doReturn(INVALID_SIM_SLOT_INDEX).when(TEST_SUBINFO_2).getSimSlotIndex();
+ doReturn(TEST_SUBSCRIPTION_ID_1).when(TEST_SUBINFO_1).getSubscriptionId();
+ doReturn(TEST_SUBSCRIPTION_ID_2).when(TEST_SUBINFO_2).getSubscriptionId();
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mCallback = mock(TelephonySubscriptionTrackerCallback.class);
+ mTelephonySubscriptionTracker =
+ new TelephonySubscriptionTracker(mContext, mHandler, mCallback, mDeps);
+ mTelephonySubscriptionTracker.register();
+
+ doReturn(true).when(mDeps).isConfigForIdentifiedCarrier(any());
+ doReturn(Arrays.asList(TEST_SUBINFO_1, TEST_SUBINFO_2))
+ .when(mSubscriptionManager)
+ .getAllSubscriptionInfoList();
+ }
+
+ private IntentFilter getIntentFilter() {
+ final ArgumentCaptor<IntentFilter> captor = ArgumentCaptor.forClass(IntentFilter.class);
+ verify(mContext).registerReceiver(any(), captor.capture(), any(), any());
+
+ return captor.getValue();
+ }
+
+ private OnSubscriptionsChangedListener getOnSubscriptionsChangedListener() {
+ final ArgumentCaptor<OnSubscriptionsChangedListener> captor =
+ ArgumentCaptor.forClass(OnSubscriptionsChangedListener.class);
+ verify(mSubscriptionManager).addOnSubscriptionsChangedListener(any(), captor.capture());
+
+ return captor.getValue();
+ }
+
+ private Intent buildTestBroadcastIntent(boolean hasValidSubscription) {
+ Intent intent = new Intent(ACTION_CARRIER_CONFIG_CHANGED);
+ intent.putExtra(EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX);
+ intent.putExtra(
+ EXTRA_SUBSCRIPTION_INDEX,
+ hasValidSubscription ? TEST_SUBSCRIPTION_ID_1 : INVALID_SUBSCRIPTION_ID);
+
+ return intent;
+ }
+
+ private TelephonySubscriptionSnapshot buildExpectedSnapshot(Set<ParcelUuid> activeSubGroups) {
+ return buildExpectedSnapshot(TEST_SUBID_TO_GROUP_MAP, activeSubGroups);
+ }
+
+ private TelephonySubscriptionSnapshot buildExpectedSnapshot(
+ Map<Integer, ParcelUuid> subIdToGroupMap, Set<ParcelUuid> activeSubGroups) {
+ return new TelephonySubscriptionSnapshot(subIdToGroupMap, activeSubGroups);
+ }
+
+ private void verifyNoActiveSubscriptions() {
+ verify(mCallback).onNewSnapshot(
+ argThat(snapshot -> snapshot.getActiveSubscriptionGroups().isEmpty()));
+ }
+
+ private void setupReadySubIds() {
+ mTelephonySubscriptionTracker.setReadySubIdsBySlotId(
+ Collections.singletonMap(TEST_SIM_SLOT_INDEX, TEST_SUBSCRIPTION_ID_1));
+ }
+
+ @Test
+ public void testRegister() throws Exception {
+ verify(mContext)
+ .registerReceiver(
+ eq(mTelephonySubscriptionTracker),
+ any(IntentFilter.class),
+ any(),
+ eq(mHandler));
+ final IntentFilter filter = getIntentFilter();
+ assertEquals(1, filter.countActions());
+ assertTrue(filter.hasAction(ACTION_CARRIER_CONFIG_CHANGED));
+
+ verify(mSubscriptionManager)
+ .addOnSubscriptionsChangedListener(any(HandlerExecutor.class), any());
+ assertNotNull(getOnSubscriptionsChangedListener());
+ }
+
+ @Test
+ public void testUnregister() throws Exception {
+ mTelephonySubscriptionTracker.unregister();
+
+ verify(mContext).unregisterReceiver(eq(mTelephonySubscriptionTracker));
+
+ final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener();
+ verify(mSubscriptionManager).removeOnSubscriptionsChangedListener(eq(listener));
+ }
+
+ @Test
+ public void testOnSubscriptionsChangedFired_NoReadySubIds() throws Exception {
+ final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener();
+ listener.onSubscriptionsChanged();
+ mTestLooper.dispatchAll();
+
+ verifyNoActiveSubscriptions();
+ }
+
+ @Test
+ public void testOnSubscriptionsChangedFired_WithReadySubIds() throws Exception {
+ setupReadySubIds();
+
+ final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener();
+ listener.onSubscriptionsChanged();
+ mTestLooper.dispatchAll();
+
+ final Set<ParcelUuid> activeSubGroups = Collections.singleton(TEST_PARCEL_UUID);
+ verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(activeSubGroups)));
+ }
+
+ @Test
+ public void testReceiveBroadcast_ConfigReadyWithSubscriptions() throws Exception {
+ mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ mTestLooper.dispatchAll();
+
+ final Set<ParcelUuid> activeSubGroups = Collections.singleton(TEST_PARCEL_UUID);
+ verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(activeSubGroups)));
+ }
+
+ @Test
+ public void testReceiveBroadcast_ConfigReadyNoSubscriptions() throws Exception {
+ doReturn(new ArrayList<SubscriptionInfo>())
+ .when(mSubscriptionManager)
+ .getAllSubscriptionInfoList();
+
+ mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ mTestLooper.dispatchAll();
+
+ // Expect an empty snapshot
+ verify(mCallback).onNewSnapshot(
+ eq(buildExpectedSnapshot(Collections.emptyMap(), Collections.emptySet())));
+ }
+
+ @Test
+ public void testReceiveBroadcast_SlotCleared() throws Exception {
+ setupReadySubIds();
+
+ mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(false));
+ mTestLooper.dispatchAll();
+
+ verifyNoActiveSubscriptions();
+ assertTrue(mTelephonySubscriptionTracker.getReadySubIdsBySlotId().isEmpty());
+ }
+
+ @Test
+ public void testReceiveBroadcast_ConfigNotReady() throws Exception {
+ doReturn(false).when(mDeps).isConfigForIdentifiedCarrier(any());
+
+ mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ mTestLooper.dispatchAll();
+
+ // No interactions expected; config was not loaded
+ verifyNoMoreInteractions(mCallback);
+ }
+
+ @Test
+ public void testSubscriptionsClearedAfterValidTriggersCallbacks() throws Exception {
+ final Set<ParcelUuid> activeSubGroups = Collections.singleton(TEST_PARCEL_UUID);
+
+ mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ mTestLooper.dispatchAll();
+ verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(activeSubGroups)));
+ assertNotNull(
+ mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX));
+
+ doReturn(Collections.emptyList()).when(mSubscriptionManager).getAllSubscriptionInfoList();
+ mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ mTestLooper.dispatchAll();
+ verify(mCallback).onNewSnapshot(
+ eq(buildExpectedSnapshot(Collections.emptyMap(), Collections.emptySet())));
+ }
+
+ @Test
+ public void testSlotClearedAfterValidTriggersCallbacks() throws Exception {
+ final Set<ParcelUuid> activeSubGroups = Collections.singleton(TEST_PARCEL_UUID);
+
+ mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ mTestLooper.dispatchAll();
+ verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(activeSubGroups)));
+ assertNotNull(
+ mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX));
+
+ mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(false));
+ mTestLooper.dispatchAll();
+ verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(Collections.emptySet())));
+ assertNull(mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX));
+ }
+
+ @Test
+ public void testTelephonySubscriptionSnapshotGetGroupForSubId() throws Exception {
+ final TelephonySubscriptionSnapshot snapshot =
+ new TelephonySubscriptionSnapshot(TEST_SUBID_TO_GROUP_MAP, Collections.emptySet());
+
+ assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_1));
+ assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_2));
+ }
+
+ @Test
+ public void testTelephonySubscriptionSnapshotGetAllSubIdsInGroup() throws Exception {
+ final TelephonySubscriptionSnapshot snapshot =
+ new TelephonySubscriptionSnapshot(TEST_SUBID_TO_GROUP_MAP, Collections.emptySet());
+
+ assertEquals(
+ new ArraySet<>(Arrays.asList(TEST_SUBSCRIPTION_ID_1, TEST_SUBSCRIPTION_ID_2)),
+ snapshot.getAllSubIdsInGroup(TEST_PARCEL_UUID));
+ }
+}
diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp
index 28330db..d7a8e6f 100644
--- a/tools/aapt2/util/Util.cpp
+++ b/tools/aapt2/util/Util.cpp
@@ -548,14 +548,14 @@
}
StringPiece16 GetString16(const android::ResStringPool& pool, size_t idx) {
- if (auto str = pool.stringAt(idx)) {
+ if (auto str = pool.stringAt(idx); str.ok()) {
return *str;
}
return StringPiece16();
}
std::string GetString(const android::ResStringPool& pool, size_t idx) {
- if (auto str = pool.string8At(idx)) {
+ if (auto str = pool.string8At(idx); str.ok()) {
return ModifiedUtf8ToUtf8(str->to_string());
}
return Utf16ToUtf8(GetString16(pool, idx));
diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp
index 950473d..991b280 100644
--- a/tools/validatekeymaps/Main.cpp
+++ b/tools/validatekeymaps/Main.cpp
@@ -96,7 +96,7 @@
case FileType::KEY_LAYOUT: {
base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(filename);
- if (!ret) {
+ if (!ret.ok()) {
error("Error %s parsing key layout file.\n\n", ret.error().message().c_str());
return false;
}
@@ -106,7 +106,7 @@
case FileType::KEY_CHARACTER_MAP: {
base::Result<std::shared_ptr<KeyCharacterMap>> ret =
KeyCharacterMap::load(filename, KeyCharacterMap::Format::ANY);
- if (!ret) {
+ if (!ret.ok()) {
error("Error %s parsing key character map file.\n\n",
ret.error().message().c_str());
return false;
diff --git a/wifi/Android.bp b/wifi/Android.bp
index c05f52c..07b2ea9 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -31,9 +31,6 @@
"java/**/*.java",
"java/**/*.aidl",
],
- exclude_srcs: [
- ":framework-wifi-non-updatable-sources"
- ],
path: "java",
visibility: ["//visibility:private"],
}
@@ -48,20 +45,6 @@
}
filegroup {
- name: "framework-wifi-non-updatable-sources",
- srcs: [
- // TODO(b/146011398) package android.net.wifi is now split amongst 2 jars: framework.jar and
- // framework-wifi.jar. This is not a good idea, should move WifiNetworkScoreCache
- // to a separate package.
- "java/android/net/wifi/SoftApConfToXmlMigrationUtil.java",
- "java/android/net/wifi/WifiNetworkScoreCache.java",
- "java/android/net/wifi/WifiMigration.java",
- "java/android/net/wifi/nl80211/*.java",
- ":libwificond_ipc_aidl",
- ],
-}
-
-filegroup {
name: "framework-wifi-annotations",
srcs: ["java/android/net/wifi/WifiAnnotations.java"],
}
@@ -69,6 +52,7 @@
// list of tests that are allowed to access @hide APIs from framework-wifi
test_access_hidden_api_whitelist = [
"//frameworks/base/wifi/tests",
+ "//frameworks/base/wifi/non-updatable/tests",
"//frameworks/opt/net/wifi/tests/wifitests:__subpackages__",
"//external/robolectric-shadows:__subpackages__",
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 06ebee4..23f47ef 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -147,6 +147,8 @@
void updateInterfaceIpState(String ifaceName, int mode);
+ boolean isDefaultCoexAlgorithmEnabled();
+
void setCoexUnsafeChannels(in List<CoexUnsafeChannel> unsafeChannels, int mandatoryRestrictions);
List<CoexUnsafeChannel> getCoexUnsafeChannels();
diff --git a/wifi/java/android/net/wifi/SecurityParams.java b/wifi/java/android/net/wifi/SecurityParams.java
index 0ab6f57..8ee2ea0 100644
--- a/wifi/java/android/net/wifi/SecurityParams.java
+++ b/wifi/java/android/net/wifi/SecurityParams.java
@@ -192,6 +192,15 @@
}
/**
+ * Get the security type of this params.
+ *
+ * @return The security type defined in {@link WifiConfiguration}.
+ */
+ public @SecurityType int getSecurityType() {
+ return mSecurityType;
+ }
+
+ /**
* Check the security type of this params.
*
* @param type the testing security type.
@@ -563,9 +572,64 @@
}
/**
+ * Create a params according to the security type.
+ *
+ * @param securityType One of the following security types:
+ * {@link WifiConfiguration#SECURITY_TYPE_OPEN},
+ * {@link WifiConfiguration#SECURITY_TYPE_WEP},
+ * {@link WifiConfiguration#SECURITY_TYPE_PSK},
+ * {@link WifiConfiguration#SECURITY_TYPE_EAP},
+ * {@link WifiConfiguration#SECURITY_TYPE_SAE},
+ * {@link WifiConfiguration#SECURITY_TYPE_OWE},
+ * {@link WifiConfiguration#SECURITY_TYPE_WAPI_PSK},
+ * {@link WifiConfiguration#SECURITY_TYPE_WAPI_CERT},
+ * {@link WifiConfiguration#SECURITY_TYPE_EAP_WPA3_ENTERPRISE},
+ * {@link WifiConfiguration#SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT},
+ *
+ * @return the corresponding security params if the security type is valid;
+ * otherwise, throw IllegalArgumentException.
+ */
+ public static @NonNull SecurityParams createSecurityParamsBySecurityType(
+ @WifiConfiguration.SecurityType int securityType) {
+ switch (securityType) {
+ case WifiConfiguration.SECURITY_TYPE_OPEN:
+ return createOpenParams();
+ case WifiConfiguration.SECURITY_TYPE_WEP:
+ return createWepParams();
+ case WifiConfiguration.SECURITY_TYPE_PSK:
+ return createWpaWpa2PersonalParams();
+ case WifiConfiguration.SECURITY_TYPE_EAP:
+ return createWpaWpa2EnterpriseParams();
+ case WifiConfiguration.SECURITY_TYPE_SAE:
+ return createWpa3PersonalParams();
+ // The value of {@link WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B} is the same as
+ // {@link #WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT}, remove it
+ // to avoid duplicate case label errors.
+ case WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT:
+ return createWpa3Enterprise192BitParams();
+ case WifiConfiguration.SECURITY_TYPE_OWE:
+ return createEnhancedOpenParams();
+ case WifiConfiguration.SECURITY_TYPE_WAPI_PSK:
+ return createWapiPskParams();
+ case WifiConfiguration.SECURITY_TYPE_WAPI_CERT:
+ return createWapiCertParams();
+ case WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE:
+ return createWpa3EnterpriseParams();
+ case WifiConfiguration.SECURITY_TYPE_OSEN:
+ return createOsenParams();
+ case WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2:
+ return SecurityParams.createPasspointParams(PASSPOINT_R2);
+ case WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3:
+ return SecurityParams.createPasspointParams(PASSPOINT_R3);
+ default:
+ throw new IllegalArgumentException("unknown security type " + securityType);
+ }
+ }
+
+ /**
* Create EAP security params.
*/
- public static @NonNull SecurityParams createWpaWpa2EnterpriseParams() {
+ private static @NonNull SecurityParams createWpaWpa2EnterpriseParams() {
SecurityParams params = new SecurityParams();
params.mSecurityType = WifiConfiguration.SECURITY_TYPE_EAP;
@@ -586,7 +650,7 @@
/**
* Create Passpoint security params.
*/
- public static @NonNull SecurityParams createPasspointParams(@PasspointRelease int release) {
+ private static @NonNull SecurityParams createPasspointParams(@PasspointRelease int release) {
SecurityParams params = new SecurityParams();
switch (release) {
case PASSPOINT_R1:
@@ -616,7 +680,7 @@
/**
* Create Enhanced Open params.
*/
- public static @NonNull SecurityParams createEnhancedOpenParams() {
+ private static @NonNull SecurityParams createEnhancedOpenParams() {
SecurityParams params = new SecurityParams();
params.mSecurityType = WifiConfiguration.SECURITY_TYPE_OWE;
@@ -639,7 +703,7 @@
/**
* Create Open params.
*/
- public static @NonNull SecurityParams createOpenParams() {
+ private static @NonNull SecurityParams createOpenParams() {
SecurityParams params = new SecurityParams();
params.mSecurityType = WifiConfiguration.SECURITY_TYPE_OPEN;
@@ -653,7 +717,7 @@
/**
* Create OSEN params.
*/
- public static @NonNull SecurityParams createOsenParams() {
+ private static @NonNull SecurityParams createOsenParams() {
SecurityParams params = new SecurityParams();
params.mSecurityType = WifiConfiguration.SECURITY_TYPE_OSEN;
@@ -672,7 +736,7 @@
/**
* Create WAPI-CERT params.
*/
- public static @NonNull SecurityParams createWapiCertParams() {
+ private static @NonNull SecurityParams createWapiCertParams() {
SecurityParams params = new SecurityParams();
params.mSecurityType = WifiConfiguration.SECURITY_TYPE_WAPI_CERT;
@@ -689,7 +753,7 @@
/**
* Create WAPI-PSK params.
*/
- public static @NonNull SecurityParams createWapiPskParams() {
+ private static @NonNull SecurityParams createWapiPskParams() {
SecurityParams params = new SecurityParams();
params.mSecurityType = WifiConfiguration.SECURITY_TYPE_WAPI_PSK;
@@ -706,7 +770,7 @@
/**
* Create WEP params.
*/
- public static @NonNull SecurityParams createWepParams() {
+ private static @NonNull SecurityParams createWepParams() {
SecurityParams params = new SecurityParams();
params.mSecurityType = WifiConfiguration.SECURITY_TYPE_WEP;
@@ -730,7 +794,7 @@
/**
* Create WPA3 Enterprise 192-bit params.
*/
- public static @NonNull SecurityParams createWpa3Enterprise192BitParams() {
+ private static @NonNull SecurityParams createWpa3Enterprise192BitParams() {
SecurityParams params = new SecurityParams();
params.mSecurityType = WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT;
@@ -758,7 +822,7 @@
/**
* Create WPA3 Enterprise params.
*/
- public static @NonNull SecurityParams createWpa3EnterpriseParams() {
+ private static @NonNull SecurityParams createWpa3EnterpriseParams() {
SecurityParams params = new SecurityParams();
params.mSecurityType = WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE;
@@ -780,7 +844,7 @@
/**
* Create WPA3 Personal params.
*/
- public static @NonNull SecurityParams createWpa3PersonalParams() {
+ private static @NonNull SecurityParams createWpa3PersonalParams() {
SecurityParams params = new SecurityParams();
params.mSecurityType = WifiConfiguration.SECURITY_TYPE_SAE;
@@ -803,7 +867,7 @@
/**
* Create WPA/WPA2 Personal params.
*/
- public static @NonNull SecurityParams createWpaWpa2PersonalParams() {
+ private static @NonNull SecurityParams createWpaWpa2PersonalParams() {
SecurityParams params = new SecurityParams();
params.mSecurityType = WifiConfiguration.SECURITY_TYPE_PSK;
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index ba4a54f..6c0b2df 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -566,11 +566,28 @@
*/
public void setSecurityParams(@SecurityType int securityType) {
// Clear existing data.
- mSecurityParamsList = new ArrayList<>();
+ mSecurityParamsList.clear();
addSecurityParams(securityType);
}
/**
+ * Set security params by the given key management mask.
+ *
+ * @param givenAllowedKeyManagement the given allowed key management mask.
+ * @hide
+ */
+ public void setSecurityParams(@NonNull BitSet givenAllowedKeyManagement) {
+ if (givenAllowedKeyManagement == null) {
+ throw new IllegalArgumentException("Invalid allowed key management mask.");
+ }
+ // Clear existing data.
+ mSecurityParamsList.clear();
+
+ allowedKeyManagement = (BitSet) givenAllowedKeyManagement.clone();
+ convertLegacyFieldsToSecurityParamsIfNeeded();
+ }
+
+ /**
* Add the various security params.
* <br>
* This API would clear existing security types and add a default one.
@@ -578,11 +595,26 @@
*/
public void setSecurityParams(SecurityParams params) {
// Clear existing data.
- mSecurityParamsList = new ArrayList<>();
+ mSecurityParamsList.clear();
addSecurityParams(params);
}
/**
+ * Set the security params by the given security params list.
+ *
+ * This will overwrite existing security params list directly.
+ *
+ * @param securityParamsList the desired security params list.
+ * @hide
+ */
+ public void setSecurityParams(@NonNull List<SecurityParams> securityParamsList) {
+ if (securityParamsList == null || securityParamsList.isEmpty()) {
+ throw new IllegalArgumentException("An empty security params list is invalid.");
+ }
+ mSecurityParamsList = new ArrayList<>(securityParamsList);
+ }
+
+ /**
* Add the various security params to correspond to the provided security type.
* This is accomplished by setting the various BitSets exposed in WifiConfiguration.
*
@@ -605,55 +637,7 @@
if (mSecurityParamsList.stream().anyMatch(params -> params.isSecurityType(securityType))) {
throw new IllegalArgumentException("duplicate security type " + securityType);
}
- SecurityParams params = null;
- switch (securityType) {
- case SECURITY_TYPE_OPEN:
- params = SecurityParams.createOpenParams();
- break;
- case SECURITY_TYPE_WEP:
- params = SecurityParams.createWepParams();
- break;
- case SECURITY_TYPE_PSK:
- params = SecurityParams.createWpaWpa2PersonalParams();
- break;
- case SECURITY_TYPE_EAP:
- params = SecurityParams.createWpaWpa2EnterpriseParams();
- break;
- case SECURITY_TYPE_SAE:
- params = SecurityParams.createWpa3PersonalParams();
- break;
- // The value of {@link SECURITY_TYPE_EAP_SUITE_B} is the same as
- // {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT}, remove it to avoid
- // duplicate case label errors.
- case SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT:
- params = SecurityParams.createWpa3Enterprise192BitParams();
- break;
- case SECURITY_TYPE_OWE:
- params = SecurityParams.createEnhancedOpenParams();
- break;
- case SECURITY_TYPE_WAPI_PSK:
- params = SecurityParams.createWapiPskParams();
- break;
- case SECURITY_TYPE_WAPI_CERT:
- params = SecurityParams.createWapiCertParams();
- break;
- case SECURITY_TYPE_EAP_WPA3_ENTERPRISE:
- params = SecurityParams.createWpa3EnterpriseParams();
- break;
- case SECURITY_TYPE_OSEN:
- params = SecurityParams.createOsenParams();
- break;
- case SECURITY_TYPE_PASSPOINT_R1_R2:
- params = SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R2);
- break;
- case SECURITY_TYPE_PASSPOINT_R3:
- params = SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R3);
- break;
- default:
- throw new IllegalArgumentException("unknown security type " + securityType);
- }
-
- addSecurityParams(params);
+ addSecurityParams(SecurityParams.createSecurityParamsBySecurityType(securityType));
}
/** @hide */
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index d7fcd54..5618ee8 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -3225,6 +3225,19 @@
public @interface CoexRestriction {}
/**
+ * @return {@code true} if the default coex algorithm is enabled. {@code false} otherwise.
+ *
+ * @hide
+ */
+ public boolean isDefaultCoexAlgorithmEnabled() {
+ try {
+ return mService.isDefaultCoexAlgorithmEnabled();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Specify the set of {@link CoexUnsafeChannel} to propagate through the framework for
* Wi-Fi/Cellular coex channel avoidance if the default algorithm is disabled via overlay
* (i.e. config_wifiCoexDefaultAlgorithmEnabled = false). Otherwise do nothing.
diff --git a/wifi/non-updatable/java/Android.bp b/wifi/non-updatable/java/Android.bp
new file mode 100644
index 0000000..b35b4be
--- /dev/null
+++ b/wifi/non-updatable/java/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This directory contains framework Wifi APIs that are not part of the Wifi module (i.e. not
+// updatable), and are generally only called by the Wifi module.
+
+// necessary since we only want the `path` property to only refer to these files
+filegroup {
+ name: "framework-wifi-non-updatable-sources-internal",
+ srcs: ["src/**/*.java"],
+ path: "src",
+ visibility: ["//visibility:private"],
+}
+
+filegroup {
+ name: "framework-wifi-non-updatable-sources",
+ srcs: [
+ // TODO(b/146011398) package android.net.wifi is now split amongst 2 jars: framework.jar and
+ // framework-wifi.jar. This is not a good idea, should move WifiNetworkScoreCache
+ // to a separate package.
+ ":framework-wifi-non-updatable-sources-internal",
+ ":libwificond_ipc_aidl",
+ ],
+}
diff --git a/wifi/java/android/net/wifi/SoftApConfToXmlMigrationUtil.java b/wifi/non-updatable/java/src/android/net/wifi/SoftApConfToXmlMigrationUtil.java
similarity index 100%
rename from wifi/java/android/net/wifi/SoftApConfToXmlMigrationUtil.java
rename to wifi/non-updatable/java/src/android/net/wifi/SoftApConfToXmlMigrationUtil.java
diff --git a/wifi/java/android/net/wifi/WifiMigration.java b/wifi/non-updatable/java/src/android/net/wifi/WifiMigration.java
similarity index 98%
rename from wifi/java/android/net/wifi/WifiMigration.java
rename to wifi/non-updatable/java/src/android/net/wifi/WifiMigration.java
index 5792d27..4fabc0b 100755
--- a/wifi/java/android/net/wifi/WifiMigration.java
+++ b/wifi/non-updatable/java/src/android/net/wifi/WifiMigration.java
@@ -139,8 +139,8 @@
/**
* Load data from legacy shared wifi config store file.
* <p>
- * Expected AOSP format is available in the sample files under {@code /frameworks/base/wifi/
- * java/android/net/wifi/migration_samples}.
+ * Expected AOSP format is available in the sample files under {@code
+ * frameworks/base/wifi/non-updatable/migration_samples/}.
* </p>
* <p>
* Note:
@@ -218,8 +218,8 @@
/**
* Load data from legacy user wifi config store file.
* <p>
- * Expected AOSP format is available in the sample files under {@code /frameworks/base/wifi/
- * java/android/net/wifi/migration_samples}.
+ * Expected AOSP format is available in the sample files under {@code
+ * frameworks/base/wifi/non-updatable/migration_samples/}.
* </p>
* <p>
* Note:
diff --git a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java b/wifi/non-updatable/java/src/android/net/wifi/WifiNetworkScoreCache.java
similarity index 98%
rename from wifi/java/android/net/wifi/WifiNetworkScoreCache.java
rename to wifi/non-updatable/java/src/android/net/wifi/WifiNetworkScoreCache.java
index 378549d..3903658 100755
--- a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
+++ b/wifi/non-updatable/java/src/android/net/wifi/WifiNetworkScoreCache.java
@@ -89,7 +89,7 @@
@Override public final void updateScores(List<ScoredNetwork> networks) {
if (networks == null || networks.isEmpty()) {
- return;
+ return;
}
if (DBG) {
Log.d(TAG, "updateScores list size=" + networks.size());
@@ -97,7 +97,7 @@
boolean changed = false;
- synchronized(mLock) {
+ synchronized (mLock) {
for (ScoredNetwork network : networks) {
String networkKey = buildNetworkKey(network);
if (networkKey == null) {
@@ -189,7 +189,7 @@
String key = buildNetworkKey(result);
if (key == null) return null;
- synchronized(mLock) {
+ synchronized (mLock) {
ScoredNetwork network = mCache.get(key);
return network;
}
diff --git a/wifi/java/android/net/wifi/nl80211/ChannelSettings.java b/wifi/non-updatable/java/src/android/net/wifi/nl80211/ChannelSettings.java
similarity index 100%
rename from wifi/java/android/net/wifi/nl80211/ChannelSettings.java
rename to wifi/non-updatable/java/src/android/net/wifi/nl80211/ChannelSettings.java
diff --git a/wifi/java/android/net/wifi/nl80211/DeviceWiphyCapabilities.java b/wifi/non-updatable/java/src/android/net/wifi/nl80211/DeviceWiphyCapabilities.java
similarity index 100%
rename from wifi/java/android/net/wifi/nl80211/DeviceWiphyCapabilities.java
rename to wifi/non-updatable/java/src/android/net/wifi/nl80211/DeviceWiphyCapabilities.java
diff --git a/wifi/java/android/net/wifi/nl80211/HiddenNetwork.java b/wifi/non-updatable/java/src/android/net/wifi/nl80211/HiddenNetwork.java
similarity index 100%
rename from wifi/java/android/net/wifi/nl80211/HiddenNetwork.java
rename to wifi/non-updatable/java/src/android/net/wifi/nl80211/HiddenNetwork.java
diff --git a/wifi/java/android/net/wifi/nl80211/NativeScanResult.java b/wifi/non-updatable/java/src/android/net/wifi/nl80211/NativeScanResult.java
similarity index 100%
rename from wifi/java/android/net/wifi/nl80211/NativeScanResult.java
rename to wifi/non-updatable/java/src/android/net/wifi/nl80211/NativeScanResult.java
diff --git a/wifi/java/android/net/wifi/nl80211/NativeWifiClient.java b/wifi/non-updatable/java/src/android/net/wifi/nl80211/NativeWifiClient.java
similarity index 100%
rename from wifi/java/android/net/wifi/nl80211/NativeWifiClient.java
rename to wifi/non-updatable/java/src/android/net/wifi/nl80211/NativeWifiClient.java
diff --git a/wifi/java/android/net/wifi/nl80211/PnoNetwork.java b/wifi/non-updatable/java/src/android/net/wifi/nl80211/PnoNetwork.java
similarity index 100%
rename from wifi/java/android/net/wifi/nl80211/PnoNetwork.java
rename to wifi/non-updatable/java/src/android/net/wifi/nl80211/PnoNetwork.java
diff --git a/wifi/java/android/net/wifi/nl80211/PnoSettings.java b/wifi/non-updatable/java/src/android/net/wifi/nl80211/PnoSettings.java
similarity index 100%
rename from wifi/java/android/net/wifi/nl80211/PnoSettings.java
rename to wifi/non-updatable/java/src/android/net/wifi/nl80211/PnoSettings.java
diff --git a/wifi/java/android/net/wifi/nl80211/RadioChainInfo.java b/wifi/non-updatable/java/src/android/net/wifi/nl80211/RadioChainInfo.java
similarity index 100%
rename from wifi/java/android/net/wifi/nl80211/RadioChainInfo.java
rename to wifi/non-updatable/java/src/android/net/wifi/nl80211/RadioChainInfo.java
diff --git a/wifi/java/android/net/wifi/nl80211/SingleScanSettings.java b/wifi/non-updatable/java/src/android/net/wifi/nl80211/SingleScanSettings.java
similarity index 100%
rename from wifi/java/android/net/wifi/nl80211/SingleScanSettings.java
rename to wifi/non-updatable/java/src/android/net/wifi/nl80211/SingleScanSettings.java
diff --git a/wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java b/wifi/non-updatable/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
similarity index 100%
rename from wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java
rename to wifi/non-updatable/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
diff --git a/wifi/java/android/net/wifi/migration_samples/README.txt b/wifi/non-updatable/migration_samples/README.txt
similarity index 100%
rename from wifi/java/android/net/wifi/migration_samples/README.txt
rename to wifi/non-updatable/migration_samples/README.txt
diff --git a/wifi/java/android/net/wifi/migration_samples/Shared_WifiConfigStore.xml b/wifi/non-updatable/migration_samples/Shared_WifiConfigStore.xml
similarity index 100%
rename from wifi/java/android/net/wifi/migration_samples/Shared_WifiConfigStore.xml
rename to wifi/non-updatable/migration_samples/Shared_WifiConfigStore.xml
diff --git a/wifi/java/android/net/wifi/migration_samples/Shared_WifiConfigStoreSoftAp.xml b/wifi/non-updatable/migration_samples/Shared_WifiConfigStoreSoftAp.xml
similarity index 100%
rename from wifi/java/android/net/wifi/migration_samples/Shared_WifiConfigStoreSoftAp.xml
rename to wifi/non-updatable/migration_samples/Shared_WifiConfigStoreSoftAp.xml
diff --git a/wifi/java/android/net/wifi/migration_samples/User_WifiConfigStore.xml b/wifi/non-updatable/migration_samples/User_WifiConfigStore.xml
similarity index 100%
rename from wifi/java/android/net/wifi/migration_samples/User_WifiConfigStore.xml
rename to wifi/non-updatable/migration_samples/User_WifiConfigStore.xml
diff --git a/wifi/java/android/net/wifi/migration_samples/User_WifiConfigStoreNetworkSuggestions.xml b/wifi/non-updatable/migration_samples/User_WifiConfigStoreNetworkSuggestions.xml
similarity index 100%
rename from wifi/java/android/net/wifi/migration_samples/User_WifiConfigStoreNetworkSuggestions.xml
rename to wifi/non-updatable/migration_samples/User_WifiConfigStoreNetworkSuggestions.xml
diff --git a/wifi/non-updatable/tests/Android.bp b/wifi/non-updatable/tests/Android.bp
new file mode 100644
index 0000000..3f5cacf
--- /dev/null
+++ b/wifi/non-updatable/tests/Android.bp
@@ -0,0 +1,44 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "FrameworksWifiNonUpdatableApiTests",
+
+ defaults: ["framework-wifi-test-defaults"],
+
+ srcs: ["src/**/*.java"],
+
+ jacoco: {
+ include_filter: ["android.net.wifi.*"],
+ // TODO(b/147521214) need to exclude test classes
+ exclude_filter: [],
+ },
+
+ static_libs: [
+ "androidx.test.rules",
+ "frameworks-base-testutils",
+ "guava",
+ "mockito-target-minus-junit4",
+ "truth-prebuilt",
+ ],
+
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+
+ test_suites: [
+ "general-tests",
+ ],
+}
diff --git a/wifi/non-updatable/tests/AndroidManifest.xml b/wifi/non-updatable/tests/AndroidManifest.xml
new file mode 100644
index 0000000..18986fc
--- /dev/null
+++ b/wifi/non-updatable/tests/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.net.wifi.nonupdatable.test">
+
+ <application>
+ <uses-library android:name="android.test.runner"/>
+ <activity android:label="WifiTestDummyLabel"
+ android:name="WifiTestDummyName"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.net.wifi.nonupdatable.test"
+ android:label="Frameworks Wifi Non-updatable API Tests">
+ </instrumentation>
+
+</manifest>
diff --git a/wifi/non-updatable/tests/AndroidTest.xml b/wifi/non-updatable/tests/AndroidTest.xml
new file mode 100644
index 0000000..4e8bb55
--- /dev/null
+++ b/wifi/non-updatable/tests/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs Frameworks Wifi Non-updatable API Tests.">
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="test-file-name" value="FrameworksWifiNonUpdatableApiTests.apk" />
+ </target_preparer>
+
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-tag" value="FrameworksWifiNonUpdatableApiTests" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.net.wifi.nonupdatable.test" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
diff --git a/wifi/non-updatable/tests/README.md b/wifi/non-updatable/tests/README.md
new file mode 100644
index 0000000..ad535f4
--- /dev/null
+++ b/wifi/non-updatable/tests/README.md
@@ -0,0 +1,32 @@
+# Wifi Non-Updatable Framework Unit Tests
+This package contains unit tests for the non-updatable part (i.e. outside the Wifi module) of the
+Android Wifi framework APIs based on the
+[Android Testing Support Library](http://developer.android.com/tools/testing-support-library/index.html).
+The test cases are built using the [JUnit](http://junit.org/) and [Mockito](http://mockito.org/)
+libraries.
+
+## Running Tests
+The easiest way to run tests is simply run
+
+```
+atest android.net.wifi
+```
+
+To pick up changes in framework/base, you will need to:
+1. rebuild the framework library 'make -j32'
+2. sync over the updated library to the device 'adb sync'
+3. restart framework on the device 'adb shell stop' then 'adb shell start'
+
+To enable syncing data to the device for first time after clean reflash:
+1. adb disable-verity
+2. adb reboot
+3. adb remount
+
+## Adding Tests
+Tests can be added by adding classes to the src directory. JUnit4 style test cases can
+be written by simply annotating test methods with `org.junit.Test`.
+
+## Debugging Tests
+If you are trying to debug why tests are not doing what you expected, you can add android log
+statements and use logcat to view them. The beginning and end of every tests is automatically logged
+with the tag `TestRunner`.
diff --git a/wifi/tests/src/android/net/wifi/SoftApConfToXmlMigrationUtilTest.java b/wifi/non-updatable/tests/src/android/net/wifi/SoftApConfToXmlMigrationUtilTest.java
similarity index 100%
rename from wifi/tests/src/android/net/wifi/SoftApConfToXmlMigrationUtilTest.java
rename to wifi/non-updatable/tests/src/android/net/wifi/SoftApConfToXmlMigrationUtilTest.java
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java b/wifi/non-updatable/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java
similarity index 99%
rename from wifi/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java
rename to wifi/non-updatable/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java
index fdd11a3..c4967eb 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java
+++ b/wifi/non-updatable/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java
@@ -11,7 +11,7 @@
* 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
+ * limitations under the License.
*/
package android.net.wifi;
diff --git a/wifi/tests/src/android/net/wifi/nl80211/DeviceWiphyCapabilitiesTest.java b/wifi/non-updatable/tests/src/android/net/wifi/nl80211/DeviceWiphyCapabilitiesTest.java
similarity index 100%
rename from wifi/tests/src/android/net/wifi/nl80211/DeviceWiphyCapabilitiesTest.java
rename to wifi/non-updatable/tests/src/android/net/wifi/nl80211/DeviceWiphyCapabilitiesTest.java
diff --git a/wifi/tests/src/android/net/wifi/nl80211/NativeScanResultTest.java b/wifi/non-updatable/tests/src/android/net/wifi/nl80211/NativeScanResultTest.java
similarity index 100%
rename from wifi/tests/src/android/net/wifi/nl80211/NativeScanResultTest.java
rename to wifi/non-updatable/tests/src/android/net/wifi/nl80211/NativeScanResultTest.java
diff --git a/wifi/tests/src/android/net/wifi/nl80211/PnoSettingsTest.java b/wifi/non-updatable/tests/src/android/net/wifi/nl80211/PnoSettingsTest.java
similarity index 100%
rename from wifi/tests/src/android/net/wifi/nl80211/PnoSettingsTest.java
rename to wifi/non-updatable/tests/src/android/net/wifi/nl80211/PnoSettingsTest.java
diff --git a/wifi/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java b/wifi/non-updatable/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java
similarity index 100%
rename from wifi/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java
rename to wifi/non-updatable/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java
diff --git a/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java b/wifi/non-updatable/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java
similarity index 100%
rename from wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java
rename to wifi/non-updatable/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java
diff --git a/wifi/tests/Android.bp b/wifi/tests/Android.bp
index 7eba0a7..c0be244 100644
--- a/wifi/tests/Android.bp
+++ b/wifi/tests/Android.bp
@@ -39,6 +39,7 @@
"mockito-target-minus-junit4",
"modules-utils-build",
"net-tests-utils",
+ "net-utils-framework-common",
"truth-prebuilt",
],
diff --git a/wifi/tests/src/android/net/wifi/SecurityParamsTest.java b/wifi/tests/src/android/net/wifi/SecurityParamsTest.java
index 2f6b724..c586ded 100644
--- a/wifi/tests/src/android/net/wifi/SecurityParamsTest.java
+++ b/wifi/tests/src/android/net/wifi/SecurityParamsTest.java
@@ -50,6 +50,7 @@
int[] expectedAllowedGroupCiphers,
boolean expectedRequirePmf) {
assertTrue(params.isSecurityType(expectedSecurityType));
+ assertEquals(expectedSecurityType, params.getSecurityType());
for (int b: expectedAllowedKeyManagement) {
assertTrue(params.getAllowedKeyManagement().get(b));
}
@@ -68,10 +69,32 @@
assertEquals(expectedRequirePmf, params.isRequirePmf());
}
+ /** Verify the security params created by security type. */
+ @Test
+ public void testSecurityTypeCreator() throws Exception {
+ int[] securityTypes = new int[] {
+ WifiConfiguration.SECURITY_TYPE_WAPI_CERT,
+ WifiConfiguration.SECURITY_TYPE_WAPI_PSK,
+ WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT,
+ WifiConfiguration.SECURITY_TYPE_OWE,
+ WifiConfiguration.SECURITY_TYPE_SAE,
+ WifiConfiguration.SECURITY_TYPE_OSEN,
+ WifiConfiguration.SECURITY_TYPE_EAP,
+ WifiConfiguration.SECURITY_TYPE_PSK,
+ WifiConfiguration.SECURITY_TYPE_OPEN,
+ WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2,
+ WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3,
+ };
+
+ for (int type: securityTypes) {
+ assertEquals(type,
+ SecurityParams.createSecurityParamsBySecurityType(type).getSecurityType());
+ }
+ }
+
/** Verify EAP params creator. */
@Test
public void testEapCreator() throws Exception {
- SecurityParams p = SecurityParams.createWpaWpa2EnterpriseParams();
int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_EAP;
int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WPA_EAP, KeyMgmt.IEEE8021X};
int[] expectedAllowedProtocols = new int[] {};
@@ -79,16 +102,17 @@
int[] expectedAllowedPairwiseCiphers = new int[] {};
int[] expectedAllowedGroupCiphers = new int[] {};
boolean expectedRequirePmf = false;
+ SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+ expectedSecurityType);
verifySecurityParams(p, expectedSecurityType,
expectedAllowedKeyManagement, expectedAllowedProtocols,
expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
expectedAllowedGroupCiphers, expectedRequirePmf);
}
- /** Verify Passpoint R1 params creator. */
+ /** Verify Passpoint R1/R2 params creator. */
@Test
- public void testEapPasspointR1Creator() throws Exception {
- SecurityParams p = SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R1);
+ public void testEapPasspointR1R2Creator() throws Exception {
int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2;
int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WPA_EAP, KeyMgmt.IEEE8021X};
int[] expectedAllowedProtocols = new int[] {};
@@ -96,23 +120,8 @@
int[] expectedAllowedPairwiseCiphers = new int[] {};
int[] expectedAllowedGroupCiphers = new int[] {};
boolean expectedRequirePmf = false;
- verifySecurityParams(p, expectedSecurityType,
- expectedAllowedKeyManagement, expectedAllowedProtocols,
- expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
- expectedAllowedGroupCiphers, expectedRequirePmf);
- }
-
- /** Verify Passpoint R2 params creator. */
- @Test
- public void testEapPasspointR2Creator() throws Exception {
- SecurityParams p = SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R2);
- int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2;
- int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WPA_EAP, KeyMgmt.IEEE8021X};
- int[] expectedAllowedProtocols = new int[] {};
- int[] expectedAllowedAuthAlgorithms = new int[] {};
- int[] expectedAllowedPairwiseCiphers = new int[] {};
- int[] expectedAllowedGroupCiphers = new int[] {};
- boolean expectedRequirePmf = false;
+ SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+ expectedSecurityType);
verifySecurityParams(p, expectedSecurityType,
expectedAllowedKeyManagement, expectedAllowedProtocols,
expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -122,7 +131,6 @@
/** Verify Passpoint R3 params creator. */
@Test
public void testEapPasspointR3Creator() throws Exception {
- SecurityParams p = SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R3);
int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3;
int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WPA_EAP, KeyMgmt.IEEE8021X};
int[] expectedAllowedProtocols = new int[] {};
@@ -130,6 +138,8 @@
int[] expectedAllowedPairwiseCiphers = new int[] {};
int[] expectedAllowedGroupCiphers = new int[] {};
boolean expectedRequirePmf = true;
+ SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+ expectedSecurityType);
verifySecurityParams(p, expectedSecurityType,
expectedAllowedKeyManagement, expectedAllowedProtocols,
expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -139,7 +149,6 @@
/** Verify Enhanced Open params creator. */
@Test
public void testEnhancedOpenCreator() throws Exception {
- SecurityParams p = SecurityParams.createEnhancedOpenParams();
int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_OWE;
int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.OWE};
int[] expectedAllowedProtocols = new int[] {Protocol.RSN};
@@ -149,6 +158,8 @@
int[] expectedAllowedGroupCiphers = new int[] {
GroupCipher.CCMP, GroupCipher.GCMP_128, GroupCipher.GCMP_256};
boolean expectedRequirePmf = true;
+ SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+ expectedSecurityType);
verifySecurityParams(p, expectedSecurityType,
expectedAllowedKeyManagement, expectedAllowedProtocols,
expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -158,7 +169,6 @@
/** Verify Open params creator. */
@Test
public void testOpenCreator() throws Exception {
- SecurityParams p = SecurityParams.createOpenParams();
int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_OPEN;
int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.NONE};
int[] expectedAllowedProtocols = new int[] {};
@@ -166,6 +176,8 @@
int[] expectedAllowedPairwiseCiphers = new int[] {};
int[] expectedAllowedGroupCiphers = new int[] {};
boolean expectedRequirePmf = false;
+ SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+ expectedSecurityType);
verifySecurityParams(p, expectedSecurityType,
expectedAllowedKeyManagement, expectedAllowedProtocols,
expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -175,7 +187,6 @@
/** Verify OSEN params creator. */
@Test
public void testOsenCreator() throws Exception {
- SecurityParams p = SecurityParams.createOsenParams();
int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_OSEN;
int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.OSEN};
int[] expectedAllowedProtocols = new int[] {Protocol.OSEN};
@@ -183,6 +194,8 @@
int[] expectedAllowedPairwiseCiphers = new int[] {};
int[] expectedAllowedGroupCiphers = new int[] {};
boolean expectedRequirePmf = false;
+ SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+ expectedSecurityType);
verifySecurityParams(p, expectedSecurityType,
expectedAllowedKeyManagement, expectedAllowedProtocols,
expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -192,7 +205,6 @@
/** Verify WAPI CERT params creator. */
@Test
public void testWapiCertCreator() throws Exception {
- SecurityParams p = SecurityParams.createWapiCertParams();
int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_WAPI_CERT;
int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WAPI_CERT};
int[] expectedAllowedProtocols = new int[] {Protocol.WAPI};
@@ -200,6 +212,8 @@
int[] expectedAllowedPairwiseCiphers = new int[] {PairwiseCipher.SMS4};
int[] expectedAllowedGroupCiphers = new int[] {GroupCipher.SMS4};
boolean expectedRequirePmf = false;
+ SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+ expectedSecurityType);
verifySecurityParams(p, expectedSecurityType,
expectedAllowedKeyManagement, expectedAllowedProtocols,
expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -209,7 +223,6 @@
/** Verify WAPI PSK params creator. */
@Test
public void testWapiPskCreator() throws Exception {
- SecurityParams p = SecurityParams.createWapiPskParams();
int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_WAPI_PSK;
int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WAPI_PSK};
int[] expectedAllowedProtocols = new int[] {Protocol.WAPI};
@@ -217,6 +230,8 @@
int[] expectedAllowedPairwiseCiphers = new int[] {PairwiseCipher.SMS4};
int[] expectedAllowedGroupCiphers = new int[] {GroupCipher.SMS4};
boolean expectedRequirePmf = false;
+ SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+ expectedSecurityType);
verifySecurityParams(p, expectedSecurityType,
expectedAllowedKeyManagement, expectedAllowedProtocols,
expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -226,7 +241,6 @@
/** Verify WEP params creator. */
@Test
public void testWepCreator() throws Exception {
- SecurityParams p = SecurityParams.createWepParams();
int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_WEP;
int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.NONE};
int[] expectedAllowedProtocols = new int[] {};
@@ -234,6 +248,8 @@
int[] expectedAllowedPairwiseCiphers = new int[] {};
int[] expectedAllowedGroupCiphers = new int[] {};
boolean expectedRequirePmf = false;
+ SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+ expectedSecurityType);
verifySecurityParams(p, expectedSecurityType,
expectedAllowedKeyManagement, expectedAllowedProtocols,
expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -243,7 +259,6 @@
/** Verify WPA3 Enterprise 192-bit params creator. */
@Test
public void testWpa3Enterprise192BitCreator() throws Exception {
- SecurityParams p = SecurityParams.createWpa3Enterprise192BitParams();
int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT;
int[] expectedAllowedKeyManagement = new int[] {
KeyMgmt.WPA_EAP, KeyMgmt.IEEE8021X, KeyMgmt.SUITE_B_192};
@@ -253,6 +268,8 @@
PairwiseCipher.GCMP_128, PairwiseCipher.GCMP_256};
int[] expectedAllowedGroupCiphers = new int[] {GroupCipher.GCMP_128, GroupCipher.GCMP_256};
boolean expectedRequirePmf = true;
+ SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+ expectedSecurityType);
verifySecurityParams(p, expectedSecurityType,
expectedAllowedKeyManagement, expectedAllowedProtocols,
expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -264,7 +281,6 @@
/** Verify WPA3 Enterprise params creator. */
@Test
public void testWpa3EnterpriseCreator() throws Exception {
- SecurityParams p = SecurityParams.createWpa3EnterpriseParams();
int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE;
int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WPA_EAP, KeyMgmt.IEEE8021X};
int[] expectedAllowedProtocols = new int[] {Protocol.RSN};
@@ -273,6 +289,8 @@
PairwiseCipher.CCMP, PairwiseCipher.GCMP_256};
int[] expectedAllowedGroupCiphers = new int[] {GroupCipher.CCMP, GroupCipher.GCMP_256};
boolean expectedRequirePmf = true;
+ SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+ expectedSecurityType);
verifySecurityParams(p, expectedSecurityType,
expectedAllowedKeyManagement, expectedAllowedProtocols,
expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -282,7 +300,6 @@
/** Verify WPA3 Personal params creator. */
@Test
public void testWpa3PersonalCreator() throws Exception {
- SecurityParams p = SecurityParams.createWpa3PersonalParams();
int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_SAE;
int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.SAE};
int[] expectedAllowedProtocols = new int[] {Protocol.RSN};
@@ -292,6 +309,8 @@
int[] expectedAllowedGroupCiphers = new int[] {
GroupCipher.CCMP, GroupCipher.GCMP_128, GroupCipher.GCMP_256};
boolean expectedRequirePmf = true;
+ SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+ expectedSecurityType);
verifySecurityParams(p, expectedSecurityType,
expectedAllowedKeyManagement, expectedAllowedProtocols,
expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -301,7 +320,6 @@
/** Verify WPA2 Personal EAP params creator. */
@Test
public void testWpaWpa2PersonalCreator() throws Exception {
- SecurityParams p = SecurityParams.createWpaWpa2PersonalParams();
int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_PSK;
int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WPA_PSK};
int[] expectedAllowedProtocols = new int[] {};
@@ -309,6 +327,8 @@
int[] expectedAllowedPairwiseCiphers = new int[] {};
int[] expectedAllowedGroupCiphers = new int[] {};
boolean expectedRequirePmf = false;
+ SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+ expectedSecurityType);
verifySecurityParams(p, expectedSecurityType,
expectedAllowedKeyManagement, expectedAllowedProtocols,
expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -318,7 +338,8 @@
/** Verify setter/getter methods */
@Test
public void testCommonSetterGetter() throws Exception {
- SecurityParams params = SecurityParams.createWpaWpa2PersonalParams();
+ SecurityParams params = SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_PSK);
// PSK setting
BitSet allowedKeyManagement = new BitSet();
@@ -362,7 +383,8 @@
/** Verify SAE-specific methods */
@Test
public void testSaeMethods() throws Exception {
- SecurityParams p = SecurityParams.createWpa3PersonalParams();
+ SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_SAE);
assertFalse(p.isAddedByAutoUpgrade());
p.setIsAddedByAutoUpgrade(true);
@@ -380,7 +402,8 @@
/** Verify copy constructor. */
@Test
public void testCopyConstructor() throws Exception {
- SecurityParams params = SecurityParams.createWpaWpa2PersonalParams();
+ SecurityParams params = SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_PSK);
params.setEnabled(false);
params.setIsAddedByAutoUpgrade(true);
@@ -405,9 +428,12 @@
/** Check that two params are equal if and only if their types are the same. */
@Test
public void testEquals() {
- SecurityParams saeParams1 = SecurityParams.createWpa3PersonalParams();
- SecurityParams saeParams2 = SecurityParams.createWpa3PersonalParams();
- SecurityParams pskParams = SecurityParams.createWpaWpa2PersonalParams();
+ SecurityParams saeParams1 = SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_SAE);
+ SecurityParams saeParams2 = SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_SAE);
+ SecurityParams pskParams = SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_PSK);
assertEquals(saeParams1, saeParams2);
assertNotEquals(saeParams1, pskParams);
}
@@ -415,9 +441,12 @@
/** Check that hash values are the same if and only if their types are the same. */
@Test
public void testHashCode() {
- SecurityParams saeParams1 = SecurityParams.createWpa3PersonalParams();
- SecurityParams saeParams2 = SecurityParams.createWpa3PersonalParams();
- SecurityParams pskParams = SecurityParams.createWpaWpa2PersonalParams();
+ SecurityParams saeParams1 = SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_SAE);
+ SecurityParams saeParams2 = SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_SAE);
+ SecurityParams pskParams = SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_PSK);
assertEquals(saeParams1.hashCode(), saeParams2.hashCode());
assertNotEquals(saeParams1.hashCode(), pskParams.hashCode());
}
@@ -426,26 +455,38 @@
@Test
public void testIsOpenNetwork() {
SecurityParams[] openSecurityParams = new SecurityParams[] {
- SecurityParams.createEnhancedOpenParams(),
- SecurityParams.createOpenParams(),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_OWE),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_OPEN),
};
for (SecurityParams p: openSecurityParams) {
assertTrue(p.isOpenSecurityType());
}
SecurityParams[] nonOpenSecurityParams = new SecurityParams[] {
- SecurityParams.createWpaWpa2EnterpriseParams(),
- SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R1),
- SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R2),
- SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R3),
- SecurityParams.createOsenParams(),
- SecurityParams.createWapiCertParams(),
- SecurityParams.createWapiPskParams(),
- SecurityParams.createWepParams(),
- SecurityParams.createWpa3Enterprise192BitParams(),
- SecurityParams.createWpa3EnterpriseParams(),
- SecurityParams.createWpa3PersonalParams(),
- SecurityParams.createWpaWpa2PersonalParams(),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_EAP),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_OSEN),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_WAPI_PSK),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_WAPI_CERT),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_WEP),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_SAE),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_PSK),
};
for (SecurityParams p: nonOpenSecurityParams) {
assertFalse(p.isOpenSecurityType());
@@ -456,26 +497,38 @@
@Test
public void testIsEnterpriseNetwork() {
SecurityParams[] enterpriseSecurityParams = new SecurityParams[] {
- SecurityParams.createWpaWpa2EnterpriseParams(),
- SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R1),
- SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R2),
- SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R3),
- SecurityParams.createWapiCertParams(),
- SecurityParams.createWpa3Enterprise192BitParams(),
- SecurityParams.createWpa3EnterpriseParams(),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_EAP),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_WAPI_CERT),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE),
};
for (SecurityParams p: enterpriseSecurityParams) {
assertTrue(p.isEnterpriseSecurityType());
}
SecurityParams[] nonEnterpriseSecurityParams = new SecurityParams[] {
- SecurityParams.createEnhancedOpenParams(),
- SecurityParams.createOpenParams(),
- SecurityParams.createOsenParams(),
- SecurityParams.createWapiPskParams(),
- SecurityParams.createWepParams(),
- SecurityParams.createWpa3PersonalParams(),
- SecurityParams.createWpaWpa2PersonalParams(),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_OWE),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_OPEN),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_OSEN),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_WAPI_PSK),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_WEP),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_SAE),
+ SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_PSK),
};
for (SecurityParams p: nonEnterpriseSecurityParams) {
assertFalse(p.isEnterpriseSecurityType());
@@ -485,7 +538,8 @@
/** Check that parcel marshalling/unmarshalling works */
@Test
public void testParcelMethods() {
- SecurityParams params = SecurityParams.createWpa3PersonalParams();
+ SecurityParams params = SecurityParams.createSecurityParamsBySecurityType(
+ WifiConfiguration.SECURITY_TYPE_SAE);
Parcel parcelW = Parcel.obtain();
params.writeToParcel(parcelW, 0);
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index f351e61..bde44e7 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -22,6 +22,8 @@
import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OPEN;
import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OSEN;
import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OWE;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3;
import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_PSK;
import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_SAE;
import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_WAPI_CERT;
@@ -51,6 +53,8 @@
import org.junit.Before;
import org.junit.Test;
+import java.util.ArrayList;
+import java.util.BitSet;
import java.util.List;
/**
@@ -915,7 +919,7 @@
WifiConfiguration config = new WifiConfiguration();
config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE);
- config.addSecurityParams(SecurityParams.createWapiPskParams());
+ config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_WAPI_PSK);
List<SecurityParams> paramsList = config.getSecurityParamsList();
assertEquals(3, paramsList.size());
@@ -1004,18 +1008,18 @@
@Test (expected = IllegalArgumentException.class)
public void testAddDuplicateSecurityParams() {
WifiConfiguration config = new WifiConfiguration();
- config.addSecurityParams(SecurityParams.createWpaWpa2PersonalParams());
- config.addSecurityParams(SecurityParams.createWpaWpa2PersonalParams());
+ config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
+ config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
}
/** Verify that Suite-B type works as expected. */
@Test
public void testAddSuiteBSecurityType() {
WifiConfiguration config = new WifiConfiguration();
- config.addSecurityParams(SecurityParams.createWpa3EnterpriseParams());
+ config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM);
config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE);
- config.addSecurityParams(SecurityParams.createWpa3Enterprise192BitParams());
+ config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT);
assertFalse(config.isSuiteBCipherEcdheRsaEnabled());
config.enableSuiteBCiphers(false, true);
@@ -1101,22 +1105,96 @@
/** Verify the set security params by SecurityParams objects. */
@Test
public void testSetBySecurityParamsObject() {
- Pair[] securityParamsSecurityTypePairs = new Pair[] {
- new Pair<>(SecurityParams.createWapiCertParams(), SECURITY_TYPE_WAPI_CERT),
- new Pair<>(SecurityParams.createWapiPskParams(), SECURITY_TYPE_WAPI_PSK),
- new Pair<>(SecurityParams.createWpa3Enterprise192BitParams(),
- SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT),
- new Pair<>(SecurityParams.createEnhancedOpenParams(), SECURITY_TYPE_OWE),
- new Pair<>(SecurityParams.createWpa3PersonalParams(), SECURITY_TYPE_SAE),
- new Pair<>(SecurityParams.createOsenParams(), SECURITY_TYPE_OSEN),
- new Pair<>(SecurityParams.createWpaWpa2EnterpriseParams(), SECURITY_TYPE_EAP),
- new Pair<>(SecurityParams.createWpaWpa2PersonalParams(), SECURITY_TYPE_PSK),
- new Pair<>(SecurityParams.createOpenParams(), SECURITY_TYPE_OPEN),
+ int[] securityTypes = new int[] {
+ SECURITY_TYPE_WAPI_CERT,
+ SECURITY_TYPE_WAPI_PSK,
+ SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT,
+ SECURITY_TYPE_OWE,
+ SECURITY_TYPE_SAE,
+ SECURITY_TYPE_OSEN,
+ SECURITY_TYPE_EAP,
+ SECURITY_TYPE_PSK,
+ SECURITY_TYPE_OPEN,
+ SECURITY_TYPE_PASSPOINT_R1_R2,
+ SECURITY_TYPE_PASSPOINT_R3,
};
- for (Pair pair: securityParamsSecurityTypePairs) {
+ for (int type: securityTypes) {
WifiConfiguration config = new WifiConfiguration();
- config.setSecurityParams((SecurityParams) pair.first);
+ config.setSecurityParams(type);
+ assertTrue(config.isSecurityType(type));
+ assertNotNull(config.getSecurityParams(type));
+ }
+ }
+
+ /** Verify the set security params by an allowed key management mask. */
+ @Test
+ public void testSetSecurityParamsByAllowedKeyManagement() {
+ Pair[] keyMgmtSecurityTypePairs = new Pair[] {
+ new Pair<>(KeyMgmt.WAPI_CERT, SECURITY_TYPE_WAPI_CERT),
+ new Pair<>(KeyMgmt.WAPI_PSK, SECURITY_TYPE_WAPI_PSK),
+ new Pair<>(KeyMgmt.SUITE_B_192, SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT),
+ new Pair<>(KeyMgmt.OWE, SECURITY_TYPE_OWE),
+ new Pair<>(KeyMgmt.SAE, SECURITY_TYPE_SAE),
+ new Pair<>(KeyMgmt.OSEN, SECURITY_TYPE_OSEN),
+ new Pair<>(KeyMgmt.WPA2_PSK, SECURITY_TYPE_PSK),
+ new Pair<>(KeyMgmt.WPA_EAP, SECURITY_TYPE_EAP),
+ new Pair<>(KeyMgmt.WPA_PSK, SECURITY_TYPE_PSK),
+ new Pair<>(KeyMgmt.NONE, SECURITY_TYPE_OPEN),
+ };
+
+ for (Pair pair: keyMgmtSecurityTypePairs) {
+ BitSet akm = new BitSet();
+ akm.set((int) pair.first);
+ WifiConfiguration config = new WifiConfiguration();
+ config.setSecurityParams(akm);
assertNotNull(config.getSecurityParams((int) pair.second));
}
}
+
+ /** Verify the set security params by an invalid allowed key management mask. */
+ @Test (expected = IllegalArgumentException.class)
+ public void testSetSecurityParamsByInvalidAllowedKeyManagement() {
+ WifiConfiguration config = new WifiConfiguration();
+ BitSet akm = null;
+ config.setSecurityParams(akm);
+ }
+
+ /** Verify the set security params by a security params list. */
+ @Test
+ public void testSetSecurityParamsBySecurityParamsList() {
+ WifiConfiguration config = new WifiConfiguration();
+ config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM);
+ config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE);
+ config.addSecurityParams(SECURITY_TYPE_EAP);
+ config.addSecurityParams(SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
+ assertTrue(config.isSecurityType(SECURITY_TYPE_EAP));
+ assertTrue(config.isSecurityType(SECURITY_TYPE_EAP_WPA3_ENTERPRISE));
+ assertFalse(config.isSecurityType(SECURITY_TYPE_PSK));
+ assertFalse(config.isSecurityType(SECURITY_TYPE_SAE));
+
+ List<SecurityParams> list = new ArrayList<>();
+ list.add(SecurityParams.createSecurityParamsBySecurityType(SECURITY_TYPE_PSK));
+ list.add(SecurityParams.createSecurityParamsBySecurityType(SECURITY_TYPE_SAE));
+ config.setSecurityParams(list);
+ assertFalse(config.isSecurityType(SECURITY_TYPE_EAP));
+ assertFalse(config.isSecurityType(SECURITY_TYPE_EAP_WPA3_ENTERPRISE));
+ assertTrue(config.isSecurityType(SECURITY_TYPE_PSK));
+ assertTrue(config.isSecurityType(SECURITY_TYPE_SAE));
+ }
+
+ /** Verify the set security params by an empty security params list. */
+ @Test (expected = IllegalArgumentException.class)
+ public void testSetSecurityParamsByEmptySecurityParamsList() {
+ WifiConfiguration config = new WifiConfiguration();
+ List<SecurityParams> list = new ArrayList<>();
+ config.setSecurityParams(list);
+ }
+
+ /** Verify the set security params by a null security params list. */
+ @Test (expected = IllegalArgumentException.class)
+ public void testSetSecurityParamsByNullSecurityParamsList() {
+ WifiConfiguration config = new WifiConfiguration();
+ List<SecurityParams> list = null;
+ config.setSecurityParams(list);
+ }
}