Merge "Add setSystemSelectionChannels API"
diff --git a/Android.bp b/Android.bp
index b30bdaa..6d301c9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -318,6 +318,7 @@
"rs/java",
"sax/java",
"telecomm/java",
+ "wifi/aidl-export",
],
},
@@ -1308,6 +1309,7 @@
libs: [
"framework-minus-apex",
"unsupportedappusage",
+ "ike-stubs",
],
static_libs: [
"libphonenumber-platform",
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
index 6aca4a1..60c3136 100644
--- a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
+++ b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
@@ -22,6 +22,9 @@
import com.android.internal.util.Preconditions;
+import java.util.Arrays;
+import java.util.Objects;
+
/**
* An identifier to represent a blob.
*/
@@ -173,6 +176,27 @@
dest.writeString(tag);
}
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || !(obj instanceof BlobHandle)) {
+ return false;
+ }
+ final BlobHandle other = (BlobHandle) obj;
+ return this.algorithm.equals(other.algorithm)
+ && Arrays.equals(this.digest, other.digest)
+ && this.label.equals(other.label)
+ && this.expiryTimeMillis == other.expiryTimeMillis
+ && this.tag.equals(tag);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(algorithm, Arrays.hashCode(digest), label, expiryTimeMillis, tag);
+ }
+
public static final @NonNull Creator<BlobHandle> CREATOR = new Creator<BlobHandle>() {
@Override
public @NonNull BlobHandle createFromParcel(@NonNull Parcel source) {
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java b/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java
index 4395e5a..47af7c0 100644
--- a/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java
+++ b/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java
@@ -45,6 +45,11 @@
*/
@SystemService(Context.BLOB_STORE_SERVICE)
public class BlobStoreManager {
+ /** @hide */
+ public static final int COMMIT_RESULT_SUCCESS = 0;
+ /** @hide */
+ public static final int COMMIT_RESULT_ERROR = 1;
+
private final Context mContext;
private final IBlobStoreManager mService;
@@ -102,7 +107,28 @@
*/
public @NonNull Session openSession(@IntRange(from = 1) long sessionId) throws IOException {
try {
- return new Session(mService.openSession(sessionId));
+ return new Session(mService.openSession(sessionId, mContext.getOpPackageName()));
+ } catch (ParcelableException e) {
+ e.maybeRethrow(IOException.class);
+ throw new RuntimeException(e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Delete an existing session and any data that was written to that session so far.
+ *
+ * @param sessionId a unique id obtained via {@link #createSession(BlobHandle)} that
+ * represents a particular session.
+ *
+ * @throws IOException when there is an I/O error while deleting the session.
+ * @throws SecurityException when the caller does not own the session, or
+ * the session does not exist or is invalid.
+ */
+ public void deleteSession(@IntRange(from = 1) long sessionId) throws IOException {
+ try {
+ mService.deleteSession(sessionId, mContext.getOpPackageName());
} catch (ParcelableException e) {
e.maybeRethrow(IOException.class);
throw new RuntimeException(e);
@@ -142,6 +168,9 @@
* <p> Any active leases will be automatically released when the blob's expiry time
* ({@link BlobHandle#getExpiryTimeMillis()}) is elapsed.
*
+ * <p> This lease information is persisted and calling this more than once will result in
+ * latest lease overriding any previous lease.
+ *
* @param blobHandle the {@link BlobHandle} representing the blob that the caller wants to
* acquire a lease for.
* @param descriptionResId the resource id for a short description string that can be surfaced
@@ -190,6 +219,9 @@
* <p> Any active leases will be automatically released when the blob's expiry time
* ({@link BlobHandle#getExpiryTimeMillis()}) is elapsed.
*
+ * <p> This lease information is persisted and calling this more than once will result in
+ * latest lease overriding any previous lease.
+ *
* @param blobHandle the {@link BlobHandle} representing the blob that the caller wants to
* acquire a lease for.
* @param descriptionResId the resource id for a short description string that can be surfaced
@@ -279,7 +311,9 @@
public @NonNull ParcelFileDescriptor openWrite(@BytesLong long offsetBytes,
@BytesLong long lengthBytes) throws IOException {
try {
- return mSession.openWrite(offsetBytes, lengthBytes);
+ final ParcelFileDescriptor pfd = mSession.openWrite(offsetBytes, lengthBytes);
+ pfd.seekTo(offsetBytes);
+ return pfd;
} catch (ParcelableException e) {
e.maybeRethrow(IOException.class);
throw new RuntimeException(e);
@@ -376,6 +410,31 @@
}
/**
+ * Returns {@code true} if access has been allowed for a {@code packageName} using either
+ * {@link #allowPackageAccess(String, byte[])}.
+ * Otherwise, {@code false}.
+ *
+ * @param packageName the name of the package to check the access for.
+ * @param certificate the input bytes representing a certificate of type
+ * {@link android.content.pm.PackageManager#CERT_INPUT_SHA256}.
+ *
+ * @throws IOException when there is an I/O error while getting the access type.
+ * @throws IllegalStateException when the caller tries to get access type from a session
+ * which is closed or abandoned.
+ */
+ public boolean isPackageAccessAllowed(@NonNull String packageName,
+ @NonNull byte[] certificate) throws IOException {
+ try {
+ return mSession.isPackageAccessAllowed(packageName, certificate);
+ } catch (ParcelableException e) {
+ e.maybeRethrow(IOException.class);
+ throw new RuntimeException(e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Allow packages which are signed with the same certificate as the caller to access this
* blob data once it is committed using a {@link BlobHandle} representing the blob.
*
@@ -399,6 +458,26 @@
}
/**
+ * Returns {@code true} if access has been allowed for packages signed with the same
+ * certificate as the caller by using {@link #allowSameSignatureAccess()}.
+ * Otherwise, {@code false}.
+ *
+ * @throws IOException when there is an I/O error while getting the access type.
+ * @throws IllegalStateException when the caller tries to get access type from a session
+ * which is closed or abandoned.
+ */
+ public boolean isSameSignatureAccessAllowed() throws IOException {
+ try {
+ return mSession.isSameSignatureAccessAllowed();
+ } catch (ParcelableException e) {
+ e.maybeRethrow(IOException.class);
+ throw new RuntimeException(e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Allow any app on the device to access this blob data once it is committed using
* a {@link BlobHandle} representing the blob.
*
@@ -427,6 +506,25 @@
}
/**
+ * Returns {@code true} if public access has been allowed by using
+ * {@link #allowPublicAccess()}. Otherwise, {@code false}.
+ *
+ * @throws IOException when there is an I/O error while getting the access type.
+ * @throws IllegalStateException when the caller tries to get access type from a session
+ * which is closed or abandoned.
+ */
+ public boolean isPublicAccessAllowed() throws IOException {
+ try {
+ return mSession.isPublicAccessAllowed();
+ } catch (ParcelableException e) {
+ e.maybeRethrow(IOException.class);
+ throw new RuntimeException(e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Commit the file that was written so far to this session to the blob store maintained by
* the system.
*
@@ -439,6 +537,10 @@
* {@link BlobHandle#createWithSha256(byte[], CharSequence, long, String)} BlobHandle}
* associated with this session.
*
+ * <p> Committing the same data more than once will result in replacing the corresponding
+ * access mode (via calling one of {@link #allowPackageAccess(String, byte[])},
+ * {@link #allowSameSignatureAccess()}, etc) with the latest one.
+ *
* @param executor the executor on which result callback will be invoked.
* @param resultCallback a callback to receive the commit result. when the result is
* {@code 0}, it indicates success. Otherwise, failure.
diff --git a/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl b/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl
index b7a2f1a..dfbf78f 100644
--- a/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl
+++ b/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl
@@ -21,8 +21,9 @@
/** {@hide} */
interface IBlobStoreManager {
long createSession(in BlobHandle handle, in String packageName);
- IBlobStoreSession openSession(long sessionId);
+ IBlobStoreSession openSession(long sessionId, in String packageName);
ParcelFileDescriptor openBlob(in BlobHandle handle, in String packageName);
+ void deleteSession(long sessionId, in String packageName);
void acquireLease(in BlobHandle handle, int descriptionResId, long leaseTimeout,
in String packageName);
diff --git a/apex/blobstore/framework/java/android/app/blob/IBlobStoreSession.aidl b/apex/blobstore/framework/java/android/app/blob/IBlobStoreSession.aidl
index bb5ef3b..4ae919b 100644
--- a/apex/blobstore/framework/java/android/app/blob/IBlobStoreSession.aidl
+++ b/apex/blobstore/framework/java/android/app/blob/IBlobStoreSession.aidl
@@ -26,6 +26,10 @@
void allowSameSignatureAccess();
void allowPublicAccess();
+ boolean isPackageAccessAllowed(in String packageName, in byte[] certificate);
+ boolean isSameSignatureAccessAllowed();
+ boolean isPublicAccessAllowed();
+
long getSize();
void close();
void abandon();
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java b/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
new file mode 100644
index 0000000..357250a
--- /dev/null
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ */
+package com.android.server.blob;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.util.ArraySet;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Class for representing how a blob can be shared.
+ *
+ * Note that this class is not thread-safe, callers need to take of synchronizing access.
+ */
+class BlobAccessMode {
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, value = {
+ ACCESS_TYPE_PRIVATE,
+ ACCESS_TYPE_PUBLIC,
+ ACCESS_TYPE_SAME_SIGNATURE,
+ ACCESS_TYPE_WHITELIST,
+ })
+ @interface AccessType {}
+ static final int ACCESS_TYPE_PRIVATE = 1 << 0;
+ static final int ACCESS_TYPE_PUBLIC = 1 << 1;
+ static final int ACCESS_TYPE_SAME_SIGNATURE = 1 << 2;
+ static final int ACCESS_TYPE_WHITELIST = 1 << 3;
+
+ private int mAccessType = ACCESS_TYPE_PRIVATE;
+
+ private final ArraySet<PackageIdentifier> mWhitelistedPackages = new ArraySet<>();
+
+ void allow(BlobAccessMode other) {
+ if ((other.mAccessType & ACCESS_TYPE_WHITELIST) != 0) {
+ mWhitelistedPackages.addAll(other.mWhitelistedPackages);
+ }
+ mAccessType |= other.mAccessType;
+ }
+
+ void allowPublicAccess() {
+ mAccessType |= ACCESS_TYPE_PUBLIC;
+ }
+
+ void allowSameSignatureAccess() {
+ mAccessType |= ACCESS_TYPE_SAME_SIGNATURE;
+ }
+
+ void allowPackageAccess(@NonNull String packageName, @NonNull byte[] certificate) {
+ mAccessType |= ACCESS_TYPE_WHITELIST;
+ mWhitelistedPackages.add(PackageIdentifier.create(packageName, certificate));
+ }
+
+ boolean isPublicAccessAllowed() {
+ return (mAccessType & ACCESS_TYPE_PUBLIC) != 0;
+ }
+
+ boolean isSameSignatureAccessAllowed() {
+ return (mAccessType & ACCESS_TYPE_SAME_SIGNATURE) != 0;
+ }
+
+ boolean isPackageAccessAllowed(@NonNull String packageName, @NonNull byte[] certificate) {
+ if ((mAccessType & ACCESS_TYPE_WHITELIST) == 0) {
+ return false;
+ }
+ return mWhitelistedPackages.contains(PackageIdentifier.create(packageName, certificate));
+ }
+
+ boolean isAccessAllowedForCaller(Context context,
+ @NonNull String callingPackage, @NonNull String committerPackage) {
+ if ((mAccessType & ACCESS_TYPE_PUBLIC) != 0) {
+ return true;
+ }
+
+ final PackageManager pm = context.getPackageManager();
+ if ((mAccessType & ACCESS_TYPE_SAME_SIGNATURE) != 0) {
+ if (pm.checkSignatures(committerPackage, callingPackage)
+ == PackageManager.SIGNATURE_MATCH) {
+ return true;
+ }
+ }
+
+ if ((mAccessType & ACCESS_TYPE_WHITELIST) != 0) {
+ for (int i = 0; i < mWhitelistedPackages.size(); ++i) {
+ final PackageIdentifier packageIdentifier = mWhitelistedPackages.valueAt(i);
+ if (packageIdentifier.packageName.equals(callingPackage)
+ && pm.hasSigningCertificate(callingPackage, packageIdentifier.certificate,
+ PackageManager.CERT_INPUT_SHA256)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static final class PackageIdentifier {
+ public final String packageName;
+ public final byte[] certificate;
+
+ private PackageIdentifier(@NonNull String packageName, @NonNull byte[] certificate) {
+ this.packageName = packageName;
+ this.certificate = certificate;
+ }
+
+ public static PackageIdentifier create(@NonNull String packageName,
+ @NonNull byte[] certificate) {
+ return new PackageIdentifier(packageName, certificate);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || !(obj instanceof PackageIdentifier)) {
+ return false;
+ }
+ final PackageIdentifier other = (PackageIdentifier) obj;
+ return this.packageName.equals(other.packageName)
+ && Arrays.equals(this.certificate, other.certificate);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(packageName, Arrays.hashCode(certificate));
+ }
+ }
+}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
new file mode 100644
index 0000000..d3a2271
--- /dev/null
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
@@ -0,0 +1,211 @@
+/*
+ * 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.
+ */
+package com.android.server.blob;
+
+import static android.system.OsConstants.O_RDONLY;
+
+import android.annotation.NonNull;
+import android.app.blob.BlobHandle;
+import android.content.Context;
+import android.os.ParcelFileDescriptor;
+import android.os.RevocableFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.util.Objects;
+
+class BlobMetadata {
+ private final Object mMetadataLock = new Object();
+
+ private final Context mContext;
+ private final long mBlobId;
+ private final BlobHandle mBlobHandle;
+
+ @GuardedBy("mMetadataLock")
+ private final ArraySet<Committer> mCommitters = new ArraySet<>();
+
+ @GuardedBy("mMetadataLock")
+ private final ArraySet<Leasee> mLeasees = new ArraySet<>();
+
+ /**
+ * Contains packageName -> {RevocableFileDescriptors}.
+ *
+ * Keep track of RevocableFileDescriptors given to clients which are not yet revoked/closed so
+ * that when clients access is revoked or the blob gets deleted, we can be sure that clients
+ * do not have any reference to the blob and the space occupied by the blob can be freed.
+ */
+ @GuardedBy("mRevocableFds")
+ private final ArrayMap<String, ArraySet<RevocableFileDescriptor>> mRevocableFds =
+ new ArrayMap<>();
+
+ BlobMetadata(Context context, long blobId, BlobHandle blobHandle) {
+ mContext = context;
+ mBlobId = blobId;
+ mBlobHandle = blobHandle;
+ }
+
+ void addCommitter(String packageName, int uid, BlobAccessMode blobAccessMode) {
+ synchronized (mMetadataLock) {
+ mCommitters.add(new Committer(packageName, uid, blobAccessMode));
+ }
+ }
+
+ void addLeasee(String callingPackage, int callingUid,
+ int descriptionResId, long leaseExpiryTimeMillis) {
+ synchronized (mMetadataLock) {
+ mLeasees.add(new Leasee(callingPackage, callingUid,
+ descriptionResId, leaseExpiryTimeMillis));
+ }
+ }
+
+ void removeLeasee(String packageName, int uid) {
+ synchronized (mMetadataLock) {
+ mLeasees.remove(new Accessor(packageName, uid));
+ }
+ }
+
+ boolean isAccessAllowedForCaller(String callingPackage, int callingUid) {
+ // TODO: verify blob is still valid (expiryTime is not elapsed)
+ synchronized (mMetadataLock) {
+ // Check if packageName already holds a lease on the blob.
+ for (int i = 0, size = mLeasees.size(); i < size; ++i) {
+ final Leasee leasee = mLeasees.valueAt(i);
+ if (leasee.equals(callingPackage, callingUid)
+ && leasee.isStillValid()) {
+ return true;
+ }
+ }
+
+ for (int i = 0, size = mCommitters.size(); i < size; ++i) {
+ final Committer committer = mCommitters.valueAt(i);
+
+ // Check if the caller is the same package that committed the blob.
+ if (committer.equals(callingPackage, callingUid)) {
+ return true;
+ }
+
+ // Check if the caller is allowed access as per the access mode specified
+ // by the committer.
+ if (committer.blobAccessMode.isAccessAllowedForCaller(mContext,
+ callingPackage, committer.packageName)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ ParcelFileDescriptor openForRead(String callingPackage) throws IOException {
+ // TODO: Add limit on opened fds
+ FileDescriptor fd;
+ try {
+ fd = Os.open(BlobStoreConfig.getBlobFile(mBlobId).getPath(), O_RDONLY, 0);
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
+ }
+ synchronized (mMetadataLock) {
+ return createRevocableFdLocked(fd, callingPackage);
+ }
+ }
+
+ @GuardedBy("mMetadataLock")
+ @NonNull
+ private ParcelFileDescriptor createRevocableFdLocked(FileDescriptor fd,
+ String callingPackage) throws IOException {
+ final RevocableFileDescriptor revocableFd =
+ new RevocableFileDescriptor(mContext, fd);
+ synchronized (mRevocableFds) {
+ ArraySet<RevocableFileDescriptor> revocableFdsForPkg =
+ mRevocableFds.get(callingPackage);
+ if (revocableFdsForPkg == null) {
+ revocableFdsForPkg = new ArraySet<>();
+ mRevocableFds.put(callingPackage, revocableFdsForPkg);
+ }
+ revocableFdsForPkg.add(revocableFd);
+ }
+ revocableFd.addOnCloseListener((e) -> {
+ synchronized (mRevocableFds) {
+ final ArraySet<RevocableFileDescriptor> revocableFdsForPkg =
+ mRevocableFds.get(callingPackage);
+ if (revocableFdsForPkg != null) {
+ revocableFdsForPkg.remove(revocableFd);
+ }
+ }
+ });
+ return revocableFd.getRevocableFileDescriptor();
+ }
+
+ static final class Committer extends Accessor {
+ public final BlobAccessMode blobAccessMode;
+
+ Committer(String packageName, int uid, BlobAccessMode blobAccessMode) {
+ super(packageName, uid);
+ this.blobAccessMode = blobAccessMode;
+ }
+ }
+
+ static final class Leasee extends Accessor {
+ public final int descriptionResId;
+ public final long expiryTimeMillis;
+
+ Leasee(String packageName, int uid, int descriptionResId, long expiryTimeMillis) {
+ super(packageName, uid);
+ this.descriptionResId = descriptionResId;
+ this.expiryTimeMillis = expiryTimeMillis;
+ }
+
+ boolean isStillValid() {
+ return expiryTimeMillis == 0 || expiryTimeMillis <= System.currentTimeMillis();
+ }
+ }
+
+ static class Accessor {
+ public final String packageName;
+ public final int uid;
+
+ Accessor(String packageName, int uid) {
+ this.packageName = packageName;
+ this.uid = uid;
+ }
+
+ public boolean equals(String packageName, int uid) {
+ return this.uid == uid && this.packageName.equals(packageName);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || !(obj instanceof Accessor)) {
+ return false;
+ }
+ final Accessor other = (Accessor) obj;
+ return this.uid == other.uid && this.packageName.equals(other.packageName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(packageName, uid);
+ }
+ }
+}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
new file mode 100644
index 0000000..b9a4b17
--- /dev/null
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+package com.android.server.blob;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Environment;
+import android.util.Slog;
+
+import java.io.File;
+
+class BlobStoreConfig {
+ public static final String TAG = "BlobStore";
+
+ @Nullable
+ public static File prepareBlobFile(long sessionId) {
+ final File blobsDir = prepareBlobsDir();
+ return blobsDir == null ? null : getBlobFile(blobsDir, sessionId);
+ }
+
+ @NonNull
+ public static File getBlobFile(long sessionId) {
+ return getBlobFile(getBlobsDir(), sessionId);
+ }
+
+ @NonNull
+ private static File getBlobFile(File blobsDir, long sessionId) {
+ return new File(blobsDir, String.valueOf(sessionId));
+ }
+
+ @Nullable
+ public static File prepareBlobsDir() {
+ final File blobsDir = getBlobsDir(prepareBlobStoreRootDir());
+ if (!blobsDir.exists() && !blobsDir.mkdir()) {
+ Slog.e(TAG, "Failed to mkdir(): " + blobsDir);
+ return null;
+ }
+ return blobsDir;
+ }
+
+ @NonNull
+ public static File getBlobsDir() {
+ return getBlobsDir(getBlobStoreRootDir());
+ }
+
+ @NonNull
+ private static File getBlobsDir(File blobsRootDir) {
+ return new File(blobsRootDir, "blobs");
+ }
+
+ @Nullable
+ public static File prepareBlobStoreRootDir() {
+ final File blobStoreRootDir = getBlobStoreRootDir();
+ if (!blobStoreRootDir.exists() && !blobStoreRootDir.mkdir()) {
+ Slog.e(TAG, "Failed to mkdir(): " + blobStoreRootDir);
+ return null;
+ }
+ return blobStoreRootDir;
+ }
+
+ @NonNull
+ public static File getBlobStoreRootDir() {
+ return new File(Environment.getDataSystemDirectory(), "blobstore");
+ }
+}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index b204fee..9d60f86 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -15,58 +15,350 @@
*/
package com.android.server.blob;
+import static android.app.blob.BlobStoreManager.COMMIT_RESULT_SUCCESS;
+
+import static com.android.server.blob.BlobStoreConfig.TAG;
+import static com.android.server.blob.BlobStoreSession.STATE_ABANDONED;
+import static com.android.server.blob.BlobStoreSession.STATE_COMMITTED;
+import static com.android.server.blob.BlobStoreSession.STATE_VERIFIED_INVALID;
+import static com.android.server.blob.BlobStoreSession.STATE_VERIFIED_VALID;
+import static com.android.server.blob.BlobStoreSession.stateToString;
+
import android.annotation.CurrentTimeSecondsLong;
import android.annotation.IdRes;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.app.blob.BlobHandle;
import android.app.blob.IBlobStoreManager;
import android.app.blob.IBlobStoreSession;
import android.content.Context;
+import android.content.pm.PackageManagerInternal;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.ExceptionUtils;
+import android.util.LongSparseArray;
+import android.util.Slog;
+import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.LocalServices;
+import com.android.server.ServiceThread;
import com.android.server.SystemService;
+import com.android.server.Watchdog;
+
+import java.io.IOException;
/**
* Service responsible for maintaining and facilitating access to data blobs published by apps.
*/
public class BlobStoreManagerService extends SystemService {
+ private final Object mBlobsLock = new Object();
+
+ // Contains data of userId -> {sessionId -> {BlobStoreSession}}.
+ @GuardedBy("mBlobsLock")
+ private final SparseArray<LongSparseArray<BlobStoreSession>> mSessions = new SparseArray<>();
+
+ @GuardedBy("mBlobsLock")
+ private long mCurrentMaxSessionId;
+
+ // Contains data of userId -> {BlobHandle -> {BlobMetadata}}
+ @GuardedBy("mBlobsLock")
+ private final SparseArray<ArrayMap<BlobHandle, BlobMetadata>> mBlobsMap = new SparseArray<>();
+
private final Context mContext;
+ private final Handler mHandler;
+ private final SessionStateChangeListener mSessionStateChangeListener =
+ new SessionStateChangeListener();
+
+ private PackageManagerInternal mPackageManagerInternal;
public BlobStoreManagerService(Context context) {
super(context);
mContext = context;
+
+ final HandlerThread handlerThread = new ServiceThread(TAG,
+ Process.THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
+ handlerThread.start();
+ mHandler = new Handler(handlerThread.getLooper());
+ Watchdog.getInstance().addThread(mHandler);
}
@Override
public void onStart() {
publishBinderService(Context.BLOB_STORE_SERVICE, new Stub());
+
+ mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+ }
+
+
+ @GuardedBy("mBlobsLock")
+ private long generateNextSessionIdLocked() {
+ return ++mCurrentMaxSessionId;
+ }
+
+ @GuardedBy("mBlobsLock")
+ private LongSparseArray<BlobStoreSession> getUserSessionsLocked(int userId) {
+ LongSparseArray<BlobStoreSession> userSessions = mSessions.get(userId);
+ if (userSessions == null) {
+ userSessions = new LongSparseArray<>();
+ mSessions.put(userId, userSessions);
+ }
+ return userSessions;
+ }
+
+ @GuardedBy("mBlobsLock")
+ private ArrayMap<BlobHandle, BlobMetadata> getUserBlobsLocked(int userId) {
+ ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.get(userId);
+ if (userBlobs == null) {
+ userBlobs = new ArrayMap<>();
+ mBlobsMap.put(userId, userBlobs);
+ }
+ return userBlobs;
+ }
+
+ private long createSessionInternal(BlobHandle blobHandle,
+ int callingUid, String callingPackage) {
+ synchronized (mBlobsLock) {
+ // TODO: throw if there is already an active session associated with blobHandle.
+ final long sessionId = generateNextSessionIdLocked();
+ final BlobStoreSession session = new BlobStoreSession(mContext,
+ sessionId, blobHandle, callingUid, callingPackage,
+ mSessionStateChangeListener);
+ getUserSessionsLocked(UserHandle.getUserId(callingUid)).put(sessionId, session);
+ // TODO: persist sessions data
+ return sessionId;
+ }
+ }
+
+ private BlobStoreSession openSessionInternal(long sessionId,
+ int callingUid, String callingPackage) {
+ final BlobStoreSession session;
+ synchronized (mBlobsLock) {
+ session = getUserSessionsLocked(
+ UserHandle.getUserId(callingUid)).get(sessionId);
+ if (session == null || !session.hasAccess(callingUid, callingPackage)
+ || session.isFinalized()) {
+ throw new SecurityException("Session not found: " + sessionId);
+ }
+ }
+ session.open();
+ return session;
+ }
+
+ private void deleteSessionInternal(long sessionId,
+ int callingUid, String callingPackage) {
+ synchronized (mBlobsLock) {
+ final BlobStoreSession session = openSessionInternal(sessionId,
+ callingUid, callingPackage);
+ session.open();
+ session.abandon();
+ // TODO: persist sessions data
+ }
+ }
+
+ private ParcelFileDescriptor openBlobInternal(BlobHandle blobHandle, int callingUid,
+ String callingPackage) throws IOException {
+ synchronized (mBlobsLock) {
+ final BlobMetadata blobMetadata = getUserBlobsLocked(UserHandle.getUserId(callingUid))
+ .get(blobHandle);
+ if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller(
+ callingPackage, callingUid)) {
+ throw new SecurityException("Caller not allowed to access " + blobHandle
+ + "; callingUid=" + callingUid + ", callingPackage=" + callingPackage);
+ }
+ return blobMetadata.openForRead(callingPackage);
+ }
+ }
+
+ private void acquireLeaseInternal(BlobHandle blobHandle, int descriptionResId,
+ long leaseExpiryTimeMillis, int callingUid, String callingPackage) {
+ synchronized (mBlobsLock) {
+ final BlobMetadata blobMetadata = getUserBlobsLocked(UserHandle.getUserId(callingUid))
+ .get(blobHandle);
+ if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller(
+ callingPackage, callingUid)) {
+ throw new SecurityException("Caller not allowed to access " + blobHandle
+ + "; callingUid=" + callingUid + ", callingPackage=" + callingPackage);
+ }
+ if (leaseExpiryTimeMillis != 0 && leaseExpiryTimeMillis > blobHandle.expiryTimeMillis) {
+ throw new IllegalArgumentException(
+ "Lease expiry cannot be later than blobs expiry time");
+ }
+ blobMetadata.addLeasee(callingPackage, callingUid,
+ descriptionResId, leaseExpiryTimeMillis);
+ // TODO: persist blobs data
+ }
+ }
+
+ private void releaseLeaseInternal(BlobHandle blobHandle, int callingUid,
+ String callingPackage) {
+ synchronized (mBlobsLock) {
+ final BlobMetadata blobMetadata = getUserBlobsLocked(UserHandle.getUserId(callingUid))
+ .get(blobHandle);
+ if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller(
+ callingPackage, callingUid)) {
+ throw new SecurityException("Caller not allowed to access " + blobHandle
+ + "; callingUid=" + callingUid + ", callingPackage=" + callingPackage);
+ }
+ blobMetadata.removeLeasee(callingPackage, callingUid);
+ }
+ }
+
+ private void verifyCallingPackage(int callingUid, String callingPackage) {
+ if (mPackageManagerInternal.getPackageUid(
+ callingPackage, 0, UserHandle.getUserId(callingUid)) != callingUid) {
+ throw new SecurityException("Specified calling package [" + callingPackage
+ + "] does not match the calling uid " + callingUid);
+ }
+ }
+
+ class SessionStateChangeListener {
+ public void onStateChanged(@NonNull BlobStoreSession session) {
+ mHandler.post(PooledLambda.obtainRunnable(
+ BlobStoreManagerService::onStateChangedInternal,
+ BlobStoreManagerService.this, session));
+ }
+ }
+
+ private void onStateChangedInternal(@NonNull BlobStoreSession session) {
+ synchronized (mBlobsLock) {
+ switch (session.getState()) {
+ case STATE_ABANDONED:
+ case STATE_VERIFIED_INVALID:
+ session.getSessionFile().delete();
+ getUserSessionsLocked(UserHandle.getUserId(session.ownerUid))
+ .remove(session.sessionId);
+ break;
+ case STATE_COMMITTED:
+ session.verifyBlobData();
+ break;
+ case STATE_VERIFIED_VALID:
+ final ArrayMap<BlobHandle, BlobMetadata> userBlobs =
+ getUserBlobsLocked(UserHandle.getUserId(session.ownerUid));
+ BlobMetadata blob = userBlobs.get(session.blobHandle);
+ if (blob == null) {
+ blob = new BlobMetadata(mContext,
+ session.sessionId, session.blobHandle);
+ userBlobs.put(session.blobHandle, blob);
+ }
+ blob.addCommitter(session.ownerPackageName, session.ownerUid,
+ session.getBlobAccessMode());
+ // TODO: Persist blobs data.
+ session.sendCommitCallbackResult(COMMIT_RESULT_SUCCESS);
+ getUserSessionsLocked(UserHandle.getUserId(session.ownerUid))
+ .remove(session.sessionId);
+ break;
+ default:
+ Slog.wtf(TAG, "Invalid session state: "
+ + stateToString(session.getState()));
+ }
+ // TODO: Persist sessions data.
+ }
}
private class Stub extends IBlobStoreManager.Stub {
@Override
- public long createSession(@NonNull BlobHandle blobHandle, @NonNull String packageName) {
- return 0;
+ @IntRange(from = 1)
+ public long createSession(@NonNull BlobHandle blobHandle,
+ @NonNull String packageName) {
+ Preconditions.checkNotNull(blobHandle, "blobHandle must not be null");
+ Preconditions.checkNotNull(packageName, "packageName must not be null");
+ // TODO: verify blobHandle.algorithm is sha-256
+ // TODO: assert blobHandle is valid.
+
+ final int callingUid = Binder.getCallingUid();
+ verifyCallingPackage(callingUid, packageName);
+
+ if (Process.isIsolated(callingUid) || mPackageManagerInternal.isInstantApp(
+ packageName, UserHandle.getUserId(callingUid))) {
+ throw new SecurityException("Caller not allowed to create session; "
+ + "callingUid=" + callingUid + ", callingPackage=" + packageName);
+ }
+
+ // TODO: Verify caller request is within limits (no. of calls/blob sessions/blobs)
+ return createSessionInternal(blobHandle, callingUid, packageName);
}
@Override
- public IBlobStoreSession openSession(long sessionId) {
- return null;
+ @NonNull
+ public IBlobStoreSession openSession(@IntRange(from = 1) long sessionId,
+ @NonNull String packageName) {
+ Preconditions.checkArgumentPositive(sessionId,
+ "sessionId must be positive: " + sessionId);
+ Preconditions.checkNotNull(packageName, "packageName must not be null");
+
+ final int callingUid = Binder.getCallingUid();
+ verifyCallingPackage(callingUid, packageName);
+
+ return openSessionInternal(sessionId, callingUid, packageName);
+ }
+
+ @Override
+ public void deleteSession(@IntRange(from = 1) long sessionId,
+ @NonNull String packageName) {
+ Preconditions.checkArgumentPositive(sessionId,
+ "sessionId must be positive: " + sessionId);
+ Preconditions.checkNotNull(packageName, "packageName must not be null");
+
+ final int callingUid = Binder.getCallingUid();
+ verifyCallingPackage(callingUid, packageName);
+
+ deleteSessionInternal(sessionId, callingUid, packageName);
}
@Override
public ParcelFileDescriptor openBlob(@NonNull BlobHandle blobHandle,
@NonNull String packageName) {
- return null;
+ Preconditions.checkNotNull(blobHandle, "blobHandle must not be null");
+ Preconditions.checkNotNull(packageName, "packageName must not be null");
+
+ final int callingUid = Binder.getCallingUid();
+ verifyCallingPackage(callingUid, packageName);
+
+ if (Process.isIsolated(callingUid) || mPackageManagerInternal.isInstantApp(
+ packageName, UserHandle.getUserId(callingUid))) {
+ throw new SecurityException("Caller not allowed to open blob; "
+ + "callingUid=" + callingUid + ", callingPackage=" + packageName);
+ }
+
+ try {
+ return openBlobInternal(blobHandle, callingUid, packageName);
+ } catch (IOException e) {
+ throw ExceptionUtils.wrap(e);
+ }
}
@Override
public void acquireLease(@NonNull BlobHandle blobHandle, @IdRes int descriptionResId,
- @CurrentTimeSecondsLong long leaseTimeout, @NonNull String packageName) {
+ @CurrentTimeSecondsLong long leaseTimeoutSecs, @NonNull String packageName) {
+ Preconditions.checkNotNull(blobHandle, "blobHandle must not be null");
+ Preconditions.checkNotNull(packageName, "packageName must not be null");
+
+ final int callingUid = Binder.getCallingUid();
+ verifyCallingPackage(callingUid, packageName);
+
+ acquireLeaseInternal(blobHandle, descriptionResId, leaseTimeoutSecs,
+ callingUid, packageName);
}
@Override
public void releaseLease(@NonNull BlobHandle blobHandle, @NonNull String packageName) {
+ Preconditions.checkNotNull(blobHandle, "blobHandle must not be null");
+ Preconditions.checkNotNull(packageName, "packageName must not be null");
+
+
+ final int callingUid = Binder.getCallingUid();
+ verifyCallingPackage(callingUid, packageName);
+
+ releaseLeaseInternal(blobHandle, callingUid, packageName);
}
}
}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
index 2c38e76..29092b3 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
@@ -15,20 +15,175 @@
*/
package com.android.server.blob;
+import static android.app.blob.BlobStoreManager.COMMIT_RESULT_ERROR;
+import static android.system.OsConstants.O_CREAT;
+import static android.system.OsConstants.O_RDWR;
+import static android.system.OsConstants.SEEK_SET;
+
+import static com.android.server.blob.BlobStoreConfig.TAG;
+
import android.annotation.BytesLong;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.blob.BlobHandle;
import android.app.blob.IBlobCommitCallback;
import android.app.blob.IBlobStoreSession;
+import android.content.Context;
+import android.os.Binder;
+import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.RevocableFileDescriptor;
+import android.os.storage.StorageManager;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.ExceptionUtils;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+import com.android.server.blob.BlobStoreManagerService.SessionStateChangeListener;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Arrays;
/** TODO: add doc */
public class BlobStoreSession extends IBlobStoreSession.Stub {
+ static final int STATE_OPENED = 1;
+ static final int STATE_CLOSED = 0;
+ static final int STATE_ABANDONED = 2;
+ static final int STATE_COMMITTED = 3;
+ static final int STATE_VERIFIED_VALID = 4;
+ static final int STATE_VERIFIED_INVALID = 5;
+
+ private final Object mSessionLock = new Object();
+
+ private final Context mContext;
+ private final SessionStateChangeListener mListener;
+
+ public final BlobHandle blobHandle;
+ public final long sessionId;
+ public final int ownerUid;
+ public final String ownerPackageName;
+
+ // Do not access this directly, instead use getSessionFile().
+ private File mSessionFile;
+
+ @GuardedBy("mRevocableFds")
+ private ArrayList<RevocableFileDescriptor> mRevocableFds = new ArrayList<>();
+
+ @GuardedBy("mSessionLock")
+ private int mState = STATE_CLOSED;
+
+ @GuardedBy("mSessionLock")
+ private final BlobAccessMode mBlobAccessMode = new BlobAccessMode();
+
+ @GuardedBy("mSessionLock")
+ private IBlobCommitCallback mBlobCommitCallback;
+
+ BlobStoreSession(Context context, long sessionId, BlobHandle blobHandle,
+ int ownerUid, String ownerPackageName, SessionStateChangeListener listener) {
+ this.mContext = context;
+ this.blobHandle = blobHandle;
+ this.sessionId = sessionId;
+ this.ownerUid = ownerUid;
+ this.ownerPackageName = ownerPackageName;
+ this.mListener = listener;
+ }
+
+ boolean hasAccess(int callingUid, String callingPackageName) {
+ return ownerUid == callingUid && ownerPackageName.equals(callingPackageName);
+ }
+
+ void open() {
+ synchronized (mSessionLock) {
+ if (isFinalized()) {
+ throw new IllegalStateException("Not allowed to open session with state: "
+ + stateToString(mState));
+ }
+ mState = STATE_OPENED;
+ }
+ }
+
+ int getState() {
+ synchronized (mSessionLock) {
+ return mState;
+ }
+ }
+
+ void sendCommitCallbackResult(int result) {
+ synchronized (mSessionLock) {
+ try {
+ mBlobCommitCallback.onResult(result);
+ } catch (RemoteException e) {
+ Slog.d(TAG, "Error sending the callback result", e);
+ }
+ mBlobCommitCallback = null;
+ }
+ }
+
+ BlobAccessMode getBlobAccessMode() {
+ synchronized (mSessionLock) {
+ return mBlobAccessMode;
+ }
+ }
+
+ boolean isFinalized() {
+ synchronized (mSessionLock) {
+ return mState == STATE_COMMITTED || mState == STATE_ABANDONED;
+ }
+ }
+
@Override
@NonNull
public ParcelFileDescriptor openWrite(@BytesLong long offsetBytes,
@BytesLong long lengthBytes) {
- return null;
+ assertCallerIsOwner();
+ synchronized (mSessionLock) {
+ if (mState != STATE_OPENED) {
+ throw new IllegalStateException("Not allowed to write in state: "
+ + stateToString(mState));
+ }
+
+ try {
+ return openWriteLocked(offsetBytes, lengthBytes);
+ } catch (IOException e) {
+ throw ExceptionUtils.wrap(e);
+ }
+ }
+ }
+
+ @GuardedBy("mSessionLock")
+ @NonNull
+ private ParcelFileDescriptor openWriteLocked(@BytesLong long offsetBytes,
+ @BytesLong long lengthBytes) throws IOException {
+ // TODO: Add limit on active open sessions/writes/reads
+ FileDescriptor fd = null;
+ try {
+ final File sessionFile = getSessionFile();
+ if (sessionFile == null) {
+ throw new IllegalStateException("Couldn't get the file for this session");
+ }
+ fd = Os.open(sessionFile.getPath(), O_CREAT | O_RDWR, 0600);
+ if (offsetBytes > 0) {
+ final long curOffset = Os.lseek(fd, offsetBytes, SEEK_SET);
+ if (curOffset != offsetBytes) {
+ throw new IllegalStateException("Failed to seek " + offsetBytes
+ + "; curOffset=" + offsetBytes);
+ }
+ }
+ if (lengthBytes > 0) {
+ mContext.getSystemService(StorageManager.class).allocateBytes(fd, lengthBytes);
+ }
+ } catch (ErrnoException e) {
+ e.rethrowAsIOException();
+ }
+ return createRevocableFdLocked(fd);
}
@Override
@@ -40,25 +195,192 @@
@Override
public void allowPackageAccess(@NonNull String packageName,
@NonNull byte[] certificate) {
+ assertCallerIsOwner();
+ Preconditions.checkNotNull(packageName, "packageName must not be null");
+ synchronized (mSessionLock) {
+ if (mState != STATE_OPENED) {
+ throw new IllegalStateException("Not allowed to change access type in state: "
+ + stateToString(mState));
+ }
+ mBlobAccessMode.allowPackageAccess(packageName, certificate);
+ }
}
@Override
public void allowSameSignatureAccess() {
+ assertCallerIsOwner();
+ synchronized (mSessionLock) {
+ if (mState != STATE_OPENED) {
+ throw new IllegalStateException("Not allowed to change access type in state: "
+ + stateToString(mState));
+ }
+ mBlobAccessMode.allowSameSignatureAccess();
+ }
}
@Override
public void allowPublicAccess() {
+ assertCallerIsOwner();
+ synchronized (mSessionLock) {
+ if (mState != STATE_OPENED) {
+ throw new IllegalStateException("Not allowed to change access type in state: "
+ + stateToString(mState));
+ }
+ mBlobAccessMode.allowPublicAccess();
+ }
+ }
+
+ @Override
+ public boolean isPackageAccessAllowed(@NonNull String packageName,
+ @NonNull byte[] certificate) {
+ assertCallerIsOwner();
+ Preconditions.checkNotNull(packageName, "packageName must not be null");
+ synchronized (mSessionLock) {
+ if (mState != STATE_OPENED) {
+ throw new IllegalStateException("Not allowed to get access type in state: "
+ + stateToString(mState));
+ }
+ return mBlobAccessMode.isPackageAccessAllowed(packageName, certificate);
+ }
+ }
+
+ @Override
+ public boolean isSameSignatureAccessAllowed() {
+ assertCallerIsOwner();
+ synchronized (mSessionLock) {
+ if (mState != STATE_OPENED) {
+ throw new IllegalStateException("Not allowed to get access type in state: "
+ + stateToString(mState));
+ }
+ return mBlobAccessMode.isSameSignatureAccessAllowed();
+ }
+ }
+
+ @Override
+ public boolean isPublicAccessAllowed() {
+ assertCallerIsOwner();
+ synchronized (mSessionLock) {
+ if (mState != STATE_OPENED) {
+ throw new IllegalStateException("Not allowed to get access type in state: "
+ + stateToString(mState));
+ }
+ return mBlobAccessMode.isPublicAccessAllowed();
+ }
}
@Override
public void close() {
+ closeSession(STATE_CLOSED);
}
@Override
public void abandon() {
+ closeSession(STATE_ABANDONED);
}
@Override
public void commit(IBlobCommitCallback callback) {
+ synchronized (mSessionLock) {
+ mBlobCommitCallback = callback;
+
+ closeSession(STATE_COMMITTED);
+ }
+ }
+
+ private void closeSession(int state) {
+ assertCallerIsOwner();
+ synchronized (mSessionLock) {
+ if (mState != STATE_OPENED) {
+ if (state == STATE_CLOSED) {
+ // Just trying to close the session which is already deleted or abandoned,
+ // ignore.
+ return;
+ } else {
+ throw new IllegalStateException("Not allowed to delete or abandon a session"
+ + " with state: " + stateToString(mState));
+ }
+ }
+
+ mState = state;
+ revokeAllFdsLocked();
+
+ mListener.onStateChanged(this);
+ }
+ }
+
+ void verifyBlobData() {
+ byte[] actualDigest = null;
+ try {
+ actualDigest = FileUtils.digest(getSessionFile(), blobHandle.algorithm);
+ } catch (IOException | NoSuchAlgorithmException e) {
+ Slog.e(TAG, "Error computing the digest", e);
+ }
+ synchronized (mSessionLock) {
+ if (actualDigest != null && Arrays.equals(actualDigest, blobHandle.digest)) {
+ mState = STATE_VERIFIED_VALID;
+ // Commit callback will be sent once the data is persisted.
+ } else {
+ mState = STATE_VERIFIED_INVALID;
+ sendCommitCallbackResult(COMMIT_RESULT_ERROR);
+ }
+ mListener.onStateChanged(this);
+ }
+ }
+
+ @GuardedBy("mSessionLock")
+ private void revokeAllFdsLocked() {
+ for (int i = mRevocableFds.size() - 1; i >= 0; --i) {
+ mRevocableFds.get(i).revoke();
+ mRevocableFds.remove(i);
+ }
+ }
+
+ @GuardedBy("mSessionLock")
+ @NonNull
+ private ParcelFileDescriptor createRevocableFdLocked(FileDescriptor fd)
+ throws IOException {
+ final RevocableFileDescriptor revocableFd =
+ new RevocableFileDescriptor(mContext, fd);
+ synchronized (mRevocableFds) {
+ mRevocableFds.add(revocableFd);
+ }
+ revocableFd.addOnCloseListener((e) -> {
+ synchronized (mRevocableFds) {
+ mRevocableFds.remove(revocableFd);
+ }
+ });
+ return revocableFd.getRevocableFileDescriptor();
+ }
+
+ @Nullable
+ File getSessionFile() {
+ if (mSessionFile == null) {
+ mSessionFile = BlobStoreConfig.prepareBlobFile(sessionId);
+ }
+ return mSessionFile;
+ }
+
+ @NonNull
+ static String stateToString(int state) {
+ switch (state) {
+ case STATE_OPENED:
+ return "<opened>";
+ case STATE_CLOSED:
+ return "<closed>";
+ case STATE_ABANDONED:
+ return "<abandoned>";
+ case STATE_COMMITTED:
+ return "<committed>";
+ default:
+ Slog.wtf(TAG, "Unknown state: " + state);
+ return "<unknown>";
+ }
+ }
+
+ private void assertCallerIsOwner() {
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid != ownerUid) {
+ throw new SecurityException(ownerUid + " is not the session owner");
+ }
}
}
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index f007ea4..018037c 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -714,98 +714,6 @@
}
}
- // read high watermark for section
- private long readProcStatsHighWaterMark(int section) {
- try {
- File[] files = mBaseDir.listFiles((d, name) -> {
- return name.toLowerCase().startsWith(String.valueOf(section) + '_');
- });
- if (files == null || files.length == 0) {
- return 0;
- }
- if (files.length > 1) {
- Log.e(TAG, "Only 1 file expected for high water mark. Found " + files.length);
- }
- return Long.valueOf(files[0].getName().split("_")[1]);
- } catch (SecurityException e) {
- Log.e(TAG, "Failed to get procstats high watermark file.", e);
- } catch (NumberFormatException e) {
- Log.e(TAG, "Failed to parse file name.", e);
- }
- return 0;
- }
-
- private IProcessStats mProcessStats =
- IProcessStats.Stub.asInterface(ServiceManager.getService(ProcessStats.SERVICE_NAME));
-
- private void pullProcessStats(int section, int tagId, long elapsedNanos, long wallClockNanos,
- List<StatsLogEventWrapper> pulledData) {
- synchronized (this) {
- try {
- long lastHighWaterMark = readProcStatsHighWaterMark(section);
- List<ParcelFileDescriptor> statsFiles = new ArrayList<>();
- long highWaterMark = mProcessStats.getCommittedStats(
- lastHighWaterMark, section, true, statsFiles);
- if (statsFiles.size() != 1) {
- return;
- }
- unpackStreamedData(tagId, elapsedNanos, wallClockNanos, pulledData, statsFiles);
- new File(mBaseDir.getAbsolutePath() + "/" + section + "_"
- + lastHighWaterMark).delete();
- new File(
- mBaseDir.getAbsolutePath() + "/" + section + "_"
- + highWaterMark).createNewFile();
- } catch (IOException e) {
- Log.e(TAG, "Getting procstats failed: ", e);
- } catch (RemoteException e) {
- Log.e(TAG, "Getting procstats failed: ", e);
- } catch (SecurityException e) {
- Log.e(TAG, "Getting procstats failed: ", e);
- }
- }
- }
-
- static void unpackStreamedData(int tagId, long elapsedNanos, long wallClockNanos,
- List<StatsLogEventWrapper> pulledData, List<ParcelFileDescriptor> statsFiles)
- throws IOException {
- InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(
- statsFiles.get(0));
- int[] len = new int[1];
- byte[] stats = readFully(stream, len);
- StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos,
- wallClockNanos);
- e.writeStorage(Arrays.copyOf(stats, len[0]));
- pulledData.add(e);
- }
-
- static byte[] readFully(InputStream stream, int[] outLen) throws IOException {
- int pos = 0;
- final int initialAvail = stream.available();
- byte[] data = new byte[initialAvail > 0 ? (initialAvail + 1) : 16384];
- while (true) {
- int amt = stream.read(data, pos, data.length - pos);
- if (DEBUG) {
- Slog.i(TAG, "Read " + amt + " bytes at " + pos + " of avail " + data.length);
- }
- if (amt < 0) {
- if (DEBUG) {
- Slog.i(TAG, "**** FINISHED READING: pos=" + pos + " len=" + data.length);
- }
- outLen[0] = pos;
- return data;
- }
- pos += amt;
- if (pos >= data.length) {
- byte[] newData = new byte[pos + 16384];
- if (DEBUG) {
- Slog.i(TAG, "Copying " + pos + " bytes to new array len " + newData.length);
- }
- System.arraycopy(data, 0, newData, 0, pos);
- data = newData;
- }
- }
- }
-
private void pullDebugElapsedClock(int tagId,
long elapsedNanos, final long wallClockNanos, List<StatsLogEventWrapper> pulledData) {
final long elapsedMillis = SystemClock.elapsedRealtime();
@@ -870,17 +778,6 @@
long wallClockNanos = SystemClock.currentTimeMicro() * 1000L;
switch (tagId) {
- case StatsLog.PROC_STATS: {
- pullProcessStats(ProcessStats.REPORT_ALL, tagId, elapsedNanos, wallClockNanos, ret);
- break;
- }
-
- case StatsLog.PROC_STATS_PKG_PROC: {
- pullProcessStats(ProcessStats.REPORT_PKG_PROC_STATS, tagId, elapsedNanos,
- wallClockNanos, ret);
- break;
- }
-
case StatsLog.DEBUG_ELAPSED_CLOCK: {
pullDebugElapsedClock(tagId, elapsedNanos, wallClockNanos, ret);
break;
diff --git a/api/current.txt b/api/current.txt
index 44f9805..1be9926 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5608,11 +5608,14 @@
public static final class Notification.BubbleMetadata implements android.os.Parcelable {
method public int describeContents();
method public boolean getAutoExpandBubble();
+ method @Nullable public android.graphics.drawable.Icon getBubbleIcon();
+ method @Nullable public android.app.PendingIntent getBubbleIntent();
method @Nullable public android.app.PendingIntent getDeleteIntent();
method @Dimension(unit=android.annotation.Dimension.DP) public int getDesiredHeight();
method @DimenRes public int getDesiredHeightResId();
- method @NonNull public android.graphics.drawable.Icon getIcon();
- method @NonNull public android.app.PendingIntent getIntent();
+ method @Deprecated @NonNull public android.graphics.drawable.Icon getIcon();
+ method @Deprecated @NonNull public android.app.PendingIntent getIntent();
+ method @Nullable public String getShortcutId();
method public boolean isNotificationSuppressed();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification.BubbleMetadata> CREATOR;
@@ -5621,12 +5624,14 @@
public static final class Notification.BubbleMetadata.Builder {
ctor public Notification.BubbleMetadata.Builder();
method @NonNull public android.app.Notification.BubbleMetadata build();
+ method @NonNull public android.app.Notification.BubbleMetadata.Builder createIntentBubble(@NonNull android.app.PendingIntent, @NonNull android.graphics.drawable.Icon);
+ method @NonNull public android.app.Notification.BubbleMetadata.Builder createShortcutBubble(@NonNull String);
method @NonNull public android.app.Notification.BubbleMetadata.Builder setAutoExpandBubble(boolean);
method @NonNull public android.app.Notification.BubbleMetadata.Builder setDeleteIntent(@Nullable android.app.PendingIntent);
method @NonNull public android.app.Notification.BubbleMetadata.Builder setDesiredHeight(@Dimension(unit=android.annotation.Dimension.DP) int);
method @NonNull public android.app.Notification.BubbleMetadata.Builder setDesiredHeightResId(@DimenRes int);
- method @NonNull public android.app.Notification.BubbleMetadata.Builder setIcon(@NonNull android.graphics.drawable.Icon);
- method @NonNull public android.app.Notification.BubbleMetadata.Builder setIntent(@NonNull android.app.PendingIntent);
+ method @Deprecated @NonNull public android.app.Notification.BubbleMetadata.Builder setIcon(@NonNull android.graphics.drawable.Icon);
+ method @Deprecated @NonNull public android.app.Notification.BubbleMetadata.Builder setIntent(@NonNull android.app.PendingIntent);
method @NonNull public android.app.Notification.BubbleMetadata.Builder setSuppressNotification(boolean);
}
@@ -6762,6 +6767,13 @@
method public final android.os.IBinder onBind(android.content.Intent);
}
+ public class DevicePolicyKeyguardService extends android.app.Service {
+ ctor public DevicePolicyKeyguardService();
+ method @Nullable public void dismiss();
+ method @Nullable public final android.os.IBinder onBind(@Nullable android.content.Intent);
+ method @Nullable public android.view.SurfaceControl onSurfaceReady(@Nullable android.os.IBinder);
+ }
+
public class DevicePolicyManager {
method public void addCrossProfileIntentFilter(@NonNull android.content.ComponentName, android.content.IntentFilter, int);
method public boolean addCrossProfileWidgetProvider(@NonNull android.content.ComponentName, String);
@@ -6974,6 +6986,7 @@
method public boolean setResetPasswordToken(android.content.ComponentName, byte[]);
method public void setRestrictionsProvider(@NonNull android.content.ComponentName, @Nullable android.content.ComponentName);
method public void setScreenCaptureDisabled(@NonNull android.content.ComponentName, boolean);
+ method public void setSecondaryLockscreenEnabled(@NonNull android.content.ComponentName, boolean);
method public void setSecureSetting(@NonNull android.content.ComponentName, String, String);
method public void setSecurityLoggingEnabled(@NonNull android.content.ComponentName, boolean);
method public void setShortSupportMessage(@NonNull android.content.ComponentName, @Nullable CharSequence);
@@ -6999,6 +7012,7 @@
field public static final String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
field public static final String ACTION_ADMIN_POLICY_COMPLIANCE = "android.app.action.ADMIN_POLICY_COMPLIANCE";
field public static final String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
+ field public static final String ACTION_BIND_SECONDARY_LOCKSCREEN_SERVICE = "android.app.action.BIND_SECONDARY_LOCKSCREEN_SERVICE";
field public static final String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE";
field public static final String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
field public static final String ACTION_GET_PROVISIONING_MODE = "android.app.action.GET_PROVISIONING_MODE";
@@ -7506,6 +7520,7 @@
method public void acquireLease(@NonNull android.app.blob.BlobHandle, @IdRes int, long) throws java.io.IOException;
method public void acquireLease(@NonNull android.app.blob.BlobHandle, @IdRes int) throws java.io.IOException;
method @IntRange(from=1) public long createSession(@NonNull android.app.blob.BlobHandle) throws java.io.IOException;
+ method public void deleteSession(@IntRange(from=1) long) throws java.io.IOException;
method @NonNull public android.os.ParcelFileDescriptor openBlob(@NonNull android.app.blob.BlobHandle) throws java.io.IOException;
method @NonNull public android.app.blob.BlobStoreManager.Session openSession(@IntRange(from=1) long) throws java.io.IOException;
method public void releaseLease(@NonNull android.app.blob.BlobHandle) throws java.io.IOException;
@@ -7519,6 +7534,9 @@
method public void close() throws java.io.IOException;
method public void commit(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws java.io.IOException;
method public long getSize() throws java.io.IOException;
+ method public boolean isPackageAccessAllowed(@NonNull String, @NonNull byte[]) throws java.io.IOException;
+ method public boolean isPublicAccessAllowed() throws java.io.IOException;
+ method public boolean isSameSignatureAccessAllowed() throws java.io.IOException;
method @NonNull public android.os.ParcelFileDescriptor openWrite(long, long) throws java.io.IOException;
}
@@ -30734,9 +30752,19 @@
method @Deprecated @NonNull public android.net.MacAddress getRandomizedMacAddress();
method @Deprecated public boolean isPasspoint();
method @Deprecated public void setHttpProxy(android.net.ProxyInfo);
+ method @Deprecated public void setSecurityParams(int);
method public void writeToParcel(android.os.Parcel, int);
field @Deprecated public String BSSID;
field @Deprecated public String FQDN;
+ field @Deprecated public static final int SECURITY_TYPE_EAP = 3; // 0x3
+ field @Deprecated public static final int SECURITY_TYPE_EAP_SUITE_B = 5; // 0x5
+ field @Deprecated public static final int SECURITY_TYPE_OPEN = 0; // 0x0
+ field @Deprecated public static final int SECURITY_TYPE_OWE = 6; // 0x6
+ field @Deprecated public static final int SECURITY_TYPE_PSK = 2; // 0x2
+ field @Deprecated public static final int SECURITY_TYPE_SAE = 4; // 0x4
+ field @Deprecated public static final int SECURITY_TYPE_WAPI_CERT = 8; // 0x8
+ field @Deprecated public static final int SECURITY_TYPE_WAPI_PSK = 7; // 0x7
+ field @Deprecated public static final int SECURITY_TYPE_WEP = 1; // 0x1
field @Deprecated public String SSID;
field @Deprecated @NonNull public java.util.BitSet allowedAuthAlgorithms;
field @Deprecated @NonNull public java.util.BitSet allowedGroupCiphers;
@@ -45608,6 +45636,12 @@
field public static final int BAND_7 = 7; // 0x7
field public static final int BAND_8 = 8; // 0x8
field public static final int BAND_9 = 9; // 0x9
+ field public static final int BAND_A = 101; // 0x65
+ field public static final int BAND_B = 102; // 0x66
+ field public static final int BAND_C = 103; // 0x67
+ field public static final int BAND_D = 104; // 0x68
+ field public static final int BAND_E = 105; // 0x69
+ field public static final int BAND_F = 106; // 0x6a
}
public final class AvailableNetworkInfo implements android.os.Parcelable {
@@ -45917,6 +45951,59 @@
field public static final String KEY_WIFI_OFF_DEFERRING_TIME_INT = "ims.wifi_off_deferring_time_int";
}
+ public static final class CarrierConfigManager.Iwlan {
+ field public static final int AUTHENTICATION_METHOD_CERT = 1; // 0x1
+ field public static final int AUTHENTICATION_METHOD_EAP_ONLY = 0; // 0x0
+ field public static final int DH_GROUP_1024_BIT_MODP = 2; // 0x2
+ field public static final int DH_GROUP_2048_BIT_MODP = 14; // 0xe
+ field public static final int DH_GROUP_NONE = 0; // 0x0
+ field public static final int ENCRYPTION_ALGORITHM_3DES = 3; // 0x3
+ field public static final int ENCRYPTION_ALGORITHM_AES_CBC = 12; // 0xc
+ field public static final int ENCRYPTION_ALGORITHM_AES_GCM_12 = 19; // 0x13
+ field public static final int ENCRYPTION_ALGORITHM_AES_GCM_16 = 20; // 0x14
+ field public static final int ENCRYPTION_ALGORITHM_AES_GCM_8 = 18; // 0x12
+ field public static final int EPDG_ADDRESS_PCO = 2; // 0x2
+ field public static final int EPDG_ADDRESS_PLMN = 1; // 0x1
+ field public static final int EPDG_ADDRESS_STATIC = 0; // 0x0
+ field public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 = 5; // 0x5
+ field public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 = 2; // 0x2
+ field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 = 12; // 0xc
+ field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 = 13; // 0xd
+ field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = 14; // 0xe
+ field public static final int INTEGRITY_ALGORITHM_NONE = 0; // 0x0
+ field public static final String KEY_CHILD_SA_REKEY_HARD_TIMER_SEC_INT = "iwlan.child_sa_rekey_hard_timer_sec_int";
+ field public static final String KEY_CHILD_SA_REKEY_SOFT_TIMER_SEC_INT = "iwlan.child_sa_rekey_soft_timer_sec_int";
+ field public static final String KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY = "iwlan.child_session_aes_cbc_key_size_int_array";
+ field public static final String KEY_CHILD_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY = "iwlan.child_encryption_aes_ctr_key_size_int_array";
+ field public static final String KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY = "iwlan.diffie_hellman_groups_int_array";
+ field public static final String KEY_DPD_TIMER_SEC_INT = "iwlan.dpd_timer_sec_int";
+ field public static final String KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY = "iwlan.epdg_address_priority_int_array";
+ field public static final String KEY_EPDG_AUTHENTICATION_METHOD_INT = "iwlan.epdg_authentication_method_int";
+ field public static final String KEY_EPDG_STATIC_ADDRESS_ROAMING_STRING = "iwlan.epdg_static_address_roaming_string";
+ field public static final String KEY_EPDG_STATIC_ADDRESS_STRING = "iwlan.epdg_static_address_string";
+ field public static final String KEY_IKE_FRAGMENTATION_ENABLED_BOOL = "iwlan.ike_fragmentation_enabled_bool";
+ field public static final String KEY_IKE_REKEY_HARD_TIMER_SEC_INT = "iwlan.ike_rekey_hard_timer_in_sec";
+ field public static final String KEY_IKE_REKEY_SOFT_TIMER_SEC_INT = "iwlan.ike_rekey_soft_timer_sec_int";
+ field public static final String KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY = "iwlan.ike_session_encryption_aes_cbc_key_size_int_array";
+ field public static final String KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY = "iwlan.ike_session_aes_ctr_key_size_int_array";
+ field public static final int KEY_LEN_AES_128 = 128; // 0x80
+ field public static final int KEY_LEN_AES_192 = 192; // 0xc0
+ field public static final int KEY_LEN_AES_256 = 256; // 0x100
+ field public static final int KEY_LEN_UNUSED = 0; // 0x0
+ field public static final String KEY_MAX_RETRIES_INT = "iwlan.max_retries_int";
+ field public static final String KEY_MCC_MNCS_STRING_ARRAY = "iwlan.mcc_mncs_string_array";
+ field public static final String KEY_NATT_ENABLED_BOOL = "iwlan.natt_enabled_bool";
+ field public static final String KEY_NATT_KEEP_ALIVE_TIMER_SEC_INT = "iwlan.natt_keep_alive_timer_sec_int";
+ field public static final String KEY_PREFIX = "iwlan.";
+ field public static final String KEY_RETRANSMIT_TIMER_SEC_INT = "iwlan.retransmit_timer_sec_int";
+ field public static final String KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY = "iwlan.supported_child_session_encryption_algorithms_int_array";
+ field public static final String KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY = "iwlan.supported_ike_session_encryption_algorithms_int_array";
+ field public static final String KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY = "iwlan.supported_integrity_algorithms_int_array";
+ field public static final String KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY = "iwlan.supported_prf_algorithms_int_array";
+ field public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC = 4; // 0x4
+ field public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2; // 0x2
+ }
+
public abstract class CellIdentity implements android.os.Parcelable {
method public int describeContents();
method @Nullable public CharSequence getOperatorAlphaLong();
diff --git a/api/system-current.txt b/api/system-current.txt
index 41fca82..93c2f0c 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5,6 +5,7 @@
field public static final String ACCESS_AMBIENT_LIGHT_STATS = "android.permission.ACCESS_AMBIENT_LIGHT_STATS";
field public static final String ACCESS_BROADCAST_RADIO = "android.permission.ACCESS_BROADCAST_RADIO";
field public static final String ACCESS_CACHE_FILESYSTEM = "android.permission.ACCESS_CACHE_FILESYSTEM";
+ field public static final String ACCESS_CONTEXT_HUB = "android.permission.ACCESS_CONTEXT_HUB";
field public static final String ACCESS_DRM_CERTIFICATES = "android.permission.ACCESS_DRM_CERTIFICATES";
field @Deprecated public static final String ACCESS_FM_RADIO = "android.permission.ACCESS_FM_RADIO";
field public static final String ACCESS_INSTANT_APPS = "android.permission.ACCESS_INSTANT_APPS";
@@ -845,6 +846,7 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioningConfigApplied();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isManagedKiosk();
+ method public boolean isSecondaryLockscreenEnabled(int);
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isUnattendedManagedKiosk();
method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long);
method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long, boolean);
@@ -2903,7 +2905,7 @@
public class ContextHubClient implements java.io.Closeable {
method public void close();
method @NonNull public android.hardware.location.ContextHubInfo getAttachedHub();
- method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int sendMessageToNanoApp(@NonNull android.hardware.location.NanoAppMessage);
+ method @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public int sendMessageToNanoApp(@NonNull android.hardware.location.NanoAppMessage);
}
public class ContextHubClientCallback {
@@ -2952,24 +2954,24 @@
}
public final class ContextHubManager {
- method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.ContextHubClientCallback, @NonNull java.util.concurrent.Executor);
- method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.ContextHubClientCallback);
- method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.app.PendingIntent, long);
- method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubTransaction<java.lang.Void> disableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
- method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubTransaction<java.lang.Void> enableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
- method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int[] findNanoAppOnHub(int, @NonNull android.hardware.location.NanoAppFilter);
- method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int[] getContextHubHandles();
- method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubInfo getContextHubInfo(int);
- method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public java.util.List<android.hardware.location.ContextHubInfo> getContextHubs();
- method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.NanoAppInstanceInfo getNanoAppInstanceInfo(int);
- method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int loadNanoApp(int, @NonNull android.hardware.location.NanoApp);
- method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubTransaction<java.lang.Void> loadNanoApp(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.NanoAppBinary);
- method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubTransaction<java.util.List<android.hardware.location.NanoAppState>> queryNanoApps(@NonNull android.hardware.location.ContextHubInfo);
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.ContextHubClientCallback, @NonNull java.util.concurrent.Executor);
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.ContextHubClientCallback);
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.app.PendingIntent, long);
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubTransaction<java.lang.Void> disableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubTransaction<java.lang.Void> enableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
+ method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public int[] findNanoAppOnHub(int, @NonNull android.hardware.location.NanoAppFilter);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public int[] getContextHubHandles();
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubInfo getContextHubInfo(int);
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public java.util.List<android.hardware.location.ContextHubInfo> getContextHubs();
+ method @Deprecated @Nullable @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.NanoAppInstanceInfo getNanoAppInstanceInfo(int);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public int loadNanoApp(int, @NonNull android.hardware.location.NanoApp);
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubTransaction<java.lang.Void> loadNanoApp(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.NanoAppBinary);
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubTransaction<java.util.List<android.hardware.location.NanoAppState>> queryNanoApps(@NonNull android.hardware.location.ContextHubInfo);
method @Deprecated public int registerCallback(@NonNull android.hardware.location.ContextHubManager.Callback);
method @Deprecated public int registerCallback(android.hardware.location.ContextHubManager.Callback, android.os.Handler);
- method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int sendMessage(int, int, @NonNull android.hardware.location.ContextHubMessage);
- method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int unloadNanoApp(int);
- method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubTransaction<java.lang.Void> unloadNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public int sendMessage(int, int, @NonNull android.hardware.location.ContextHubMessage);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public int unloadNanoApp(int);
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubTransaction<java.lang.Void> unloadNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
method @Deprecated public int unregisterCallback(@NonNull android.hardware.location.ContextHubManager.Callback);
field public static final int EVENT_HUB_RESET = 6; // 0x6
field public static final int EVENT_NANOAPP_ABORTED = 4; // 0x4
@@ -4727,10 +4729,18 @@
method public void onEvent(int);
}
- public final class Tuner implements java.lang.AutoCloseable {
- ctor public Tuner(@NonNull android.content.Context);
+ public class Tuner implements java.lang.AutoCloseable {
+ ctor @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public Tuner(@NonNull android.content.Context, @NonNull String, int, @Nullable android.media.tv.tuner.Tuner.OnResourceLostListener);
method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public void clearOnTuneEventListener();
- method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public android.media.tv.tuner.Tuner.Descrambler openDescrambler();
+ method public void close();
+ method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int connectCiCam(int);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int disconnectCiCam();
+ method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int getAvSyncHwId(@NonNull android.media.tv.tuner.filter.Filter);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public long getAvSyncTime(int);
+ method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.DemuxCapabilities getDemuxCapabilities(@NonNull android.content.Context);
+ method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public android.media.tv.tuner.frontend.FrontendInfo getFrontendInfo();
+ method @Nullable public android.media.tv.tuner.frontend.FrontendStatus getFrontendStatus(@NonNull int[]);
+ method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public android.media.tv.tuner.Descrambler openDescrambler();
method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public android.media.tv.tuner.dvr.DvrPlayback openDvrPlayback(long, @Nullable java.util.concurrent.Executor, @Nullable android.media.tv.tuner.dvr.OnPlaybackStatusChangedListener);
method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public android.media.tv.tuner.dvr.DvrRecorder openDvrRecorder(long, @Nullable java.util.concurrent.Executor, @Nullable android.media.tv.tuner.dvr.OnRecordStatusChangedListener);
method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public android.media.tv.tuner.filter.Filter openFilter(int, int, long, @Nullable java.util.concurrent.Executor, @Nullable android.media.tv.tuner.filter.FilterCallback);
@@ -4738,16 +4748,21 @@
method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public android.media.tv.tuner.Lnb openLnbByName(@Nullable String, @Nullable java.util.concurrent.Executor, @NonNull android.media.tv.tuner.LnbCallback);
method @Nullable public android.media.tv.tuner.filter.TimeFilter openTimeFilter();
method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int scan(@NonNull android.media.tv.tuner.frontend.FrontendSettings, int, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.frontend.ScanCallback);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int setLna(boolean);
method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public void setOnTuneEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.frontend.OnTuneEventListener);
+ method public void shareFrontendFromTuner(@NonNull android.media.tv.tuner.Tuner);
method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int stopScan();
method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int stopTune();
method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int tune(@NonNull android.media.tv.tuner.frontend.FrontendSettings);
}
- public class Tuner.Descrambler {
+ public static interface Tuner.OnResourceLostListener {
+ method public void onResourceLost(@NonNull android.media.tv.tuner.Tuner);
}
public final class TunerConstants {
+ field public static final int INVALID_STREAM_ID = -1; // 0xffffffff
+ field public static final int INVALID_TS_PID = -1; // 0xffffffff
field public static final int RESULT_INVALID_ARGUMENT = 4; // 0x4
field public static final int RESULT_INVALID_STATE = 3; // 0x3
field public static final int RESULT_NOT_INITIALIZED = 2; // 0x2
@@ -4758,18 +4773,6 @@
field public static final int SCAN_TYPE_AUTO = 1; // 0x1
field public static final int SCAN_TYPE_BLIND = 2; // 0x2
field public static final int SCAN_TYPE_UNDEFINED = 0; // 0x0
- field public static final int SC_HEVC_INDEX_AUD = 2; // 0x2
- field public static final int SC_HEVC_INDEX_SLICE_BLA_N_LP = 16; // 0x10
- field public static final int SC_HEVC_INDEX_SLICE_BLA_W_RADL = 8; // 0x8
- field public static final int SC_HEVC_INDEX_SLICE_CE_BLA_W_LP = 4; // 0x4
- field public static final int SC_HEVC_INDEX_SLICE_IDR_N_LP = 64; // 0x40
- field public static final int SC_HEVC_INDEX_SLICE_IDR_W_RADL = 32; // 0x20
- field public static final int SC_HEVC_INDEX_SLICE_TRAIL_CRA = 128; // 0x80
- field public static final int SC_HEVC_INDEX_SPS = 1; // 0x1
- field public static final int SC_INDEX_B_FRAME = 4; // 0x4
- field public static final int SC_INDEX_I_FRAME = 1; // 0x1
- field public static final int SC_INDEX_P_FRAME = 2; // 0x2
- field public static final int SC_INDEX_SEQUENCE = 8; // 0x8
}
}
@@ -5025,6 +5028,21 @@
method public int getScIndexMask();
method public int getScIndexType();
method public int getTsIndexMask();
+ field public static final int INDEX_TYPE_NONE = 0; // 0x0
+ field public static final int INDEX_TYPE_SC = 1; // 0x1
+ field public static final int INDEX_TYPE_SC_HEVC = 2; // 0x2
+ field public static final int SC_HEVC_INDEX_AUD = 2; // 0x2
+ field public static final int SC_HEVC_INDEX_SLICE_BLA_N_LP = 16; // 0x10
+ field public static final int SC_HEVC_INDEX_SLICE_BLA_W_RADL = 8; // 0x8
+ field public static final int SC_HEVC_INDEX_SLICE_CE_BLA_W_LP = 4; // 0x4
+ field public static final int SC_HEVC_INDEX_SLICE_IDR_N_LP = 64; // 0x40
+ field public static final int SC_HEVC_INDEX_SLICE_IDR_W_RADL = 32; // 0x20
+ field public static final int SC_HEVC_INDEX_SLICE_TRAIL_CRA = 128; // 0x80
+ field public static final int SC_HEVC_INDEX_SPS = 1; // 0x1
+ field public static final int SC_INDEX_B_FRAME = 4; // 0x4
+ field public static final int SC_INDEX_I_FRAME = 1; // 0x1
+ field public static final int SC_INDEX_P_FRAME = 2; // 0x2
+ field public static final int SC_INDEX_SEQUENCE = 8; // 0x8
field public static final int TS_INDEX_ADAPTATION_EXTENSION_FLAG = 4096; // 0x1000
field public static final int TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED = 8; // 0x8
field public static final int TS_INDEX_CHANGE_TO_NOT_SCRAMBLED = 4; // 0x4
@@ -5143,6 +5161,11 @@
package android.media.tv.tuner.frontend {
+ public class AnalogFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
+ method public int getSifStandardCapability();
+ method public int getSignalTypeCapability();
+ }
+
public class AnalogFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder builder(@NonNull android.content.Context);
method public int getSifStandard();
@@ -5180,8 +5203,74 @@
public static class AnalogFrontendSettings.Builder extends android.media.tv.tuner.frontend.FrontendSettings.Builder<android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder> {
method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings build();
- method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setASignalType(int);
method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setSifStandard(int);
+ method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setSignalType(int);
+ }
+
+ public class Atsc3FrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
+ method public int getBandwidthCapability();
+ method public int getDemodOutputFormatCapability();
+ method public int getFecCapability();
+ method public int getModulationCapability();
+ method public int getPlpCodeRateCapability();
+ method public int getTimeInterleaveModeCapability();
+ }
+
+ public class Atsc3FrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
+ method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.frontend.Atsc3FrontendSettings.Builder builder(@NonNull android.content.Context);
+ method public int getBandwidth();
+ method public int getDemodOutputFormat();
+ method @NonNull public android.media.tv.tuner.frontend.Atsc3PlpSettings[] getPlpSettings();
+ method public int getType();
+ field public static final int BANDWIDTH_AUTO = 1; // 0x1
+ field public static final int BANDWIDTH_BANDWIDTH_6MHZ = 2; // 0x2
+ field public static final int BANDWIDTH_BANDWIDTH_7MHZ = 4; // 0x4
+ field public static final int BANDWIDTH_BANDWIDTH_8MHZ = 8; // 0x8
+ field public static final int BANDWIDTH_UNDEFINED = 0; // 0x0
+ field public static final int CODERATE_10_15 = 512; // 0x200
+ field public static final int CODERATE_11_15 = 1024; // 0x400
+ field public static final int CODERATE_12_15 = 2048; // 0x800
+ field public static final int CODERATE_13_15 = 4096; // 0x1000
+ field public static final int CODERATE_2_15 = 2; // 0x2
+ field public static final int CODERATE_3_15 = 4; // 0x4
+ field public static final int CODERATE_4_15 = 8; // 0x8
+ field public static final int CODERATE_5_15 = 16; // 0x10
+ field public static final int CODERATE_6_15 = 32; // 0x20
+ field public static final int CODERATE_7_15 = 64; // 0x40
+ field public static final int CODERATE_8_15 = 128; // 0x80
+ field public static final int CODERATE_9_15 = 256; // 0x100
+ field public static final int CODERATE_AUTO = 1; // 0x1
+ field public static final int CODERATE_UNDEFINED = 0; // 0x0
+ field public static final int DEMOD_OUTPUT_FORMAT_ATSC3_LINKLAYER_PACKET = 1; // 0x1
+ field public static final int DEMOD_OUTPUT_FORMAT_BASEBAND_PACKET = 2; // 0x2
+ field public static final int DEMOD_OUTPUT_FORMAT_UNDEFINED = 0; // 0x0
+ field public static final int FEC_AUTO = 1; // 0x1
+ field public static final int FEC_BCH_LDPC_16K = 2; // 0x2
+ field public static final int FEC_BCH_LDPC_64K = 4; // 0x4
+ field public static final int FEC_CRC_LDPC_16K = 8; // 0x8
+ field public static final int FEC_CRC_LDPC_64K = 16; // 0x10
+ field public static final int FEC_LDPC_16K = 32; // 0x20
+ field public static final int FEC_LDPC_64K = 64; // 0x40
+ field public static final int FEC_UNDEFINED = 0; // 0x0
+ field public static final int MODULATION_AUTO = 1; // 0x1
+ field public static final int MODULATION_MOD_1024QAM = 32; // 0x20
+ field public static final int MODULATION_MOD_16QAM = 4; // 0x4
+ field public static final int MODULATION_MOD_256QAM = 16; // 0x10
+ field public static final int MODULATION_MOD_4096QAM = 64; // 0x40
+ field public static final int MODULATION_MOD_64QAM = 8; // 0x8
+ field public static final int MODULATION_MOD_QPSK = 2; // 0x2
+ field public static final int MODULATION_UNDEFINED = 0; // 0x0
+ field public static final int TIME_INTERLEAVE_MODE_AUTO = 1; // 0x1
+ field public static final int TIME_INTERLEAVE_MODE_CTI = 2; // 0x2
+ field public static final int TIME_INTERLEAVE_MODE_HTI = 4; // 0x4
+ field public static final int TIME_INTERLEAVE_MODE_UNDEFINED = 0; // 0x0
+ }
+
+ public static class Atsc3FrontendSettings.Builder extends android.media.tv.tuner.frontend.FrontendSettings.Builder<android.media.tv.tuner.frontend.Atsc3FrontendSettings.Builder> {
+ method @NonNull public android.media.tv.tuner.frontend.Atsc3FrontendSettings build();
+ method @NonNull public android.media.tv.tuner.frontend.Atsc3FrontendSettings.Builder setBandwidth(int);
+ method @NonNull public android.media.tv.tuner.frontend.Atsc3FrontendSettings.Builder setDemodOutputFormat(byte);
+ method @NonNull public android.media.tv.tuner.frontend.Atsc3FrontendSettings.Builder setPlpSettings(@NonNull android.media.tv.tuner.frontend.Atsc3PlpSettings[]);
}
public class Atsc3PlpInfo {
@@ -5189,9 +5278,326 @@
method public int getPlpId();
}
+ public class Atsc3PlpSettings {
+ method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.frontend.Atsc3PlpSettings.Builder builder(@NonNull android.content.Context);
+ method public int getCodeRate();
+ method public int getFec();
+ method public int getInterleaveMode();
+ method public int getModulation();
+ method public int getPlpId();
+ }
+
+ public static class Atsc3PlpSettings.Builder {
+ method @NonNull public android.media.tv.tuner.frontend.Atsc3PlpSettings build();
+ method @NonNull public android.media.tv.tuner.frontend.Atsc3PlpSettings.Builder setCodeRate(int);
+ method @NonNull public android.media.tv.tuner.frontend.Atsc3PlpSettings.Builder setFec(int);
+ method @NonNull public android.media.tv.tuner.frontend.Atsc3PlpSettings.Builder setInterleaveMode(int);
+ method @NonNull public android.media.tv.tuner.frontend.Atsc3PlpSettings.Builder setModulation(int);
+ method @NonNull public android.media.tv.tuner.frontend.Atsc3PlpSettings.Builder setPlpId(int);
+ }
+
+ public class AtscFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
+ method public int getModulationCapability();
+ }
+
+ public class AtscFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
+ method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.frontend.AtscFrontendSettings.Builder builder(@NonNull android.content.Context);
+ method public int getModulation();
+ method public int getType();
+ field public static final int MODULATION_AUTO = 1; // 0x1
+ field public static final int MODULATION_MOD_16VSB = 8; // 0x8
+ field public static final int MODULATION_MOD_8VSB = 4; // 0x4
+ field public static final int MODULATION_UNDEFINED = 0; // 0x0
+ }
+
+ public static class AtscFrontendSettings.Builder extends android.media.tv.tuner.frontend.FrontendSettings.Builder<android.media.tv.tuner.frontend.AtscFrontendSettings.Builder> {
+ method @NonNull public android.media.tv.tuner.frontend.AtscFrontendSettings build();
+ method @NonNull public android.media.tv.tuner.frontend.AtscFrontendSettings.Builder setModulation(int);
+ }
+
+ public class DvbcFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
+ method public int getAnnexCapability();
+ method public int getFecCapability();
+ method public int getModulationCapability();
+ }
+
+ public class DvbcFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
+ method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder builder(@NonNull android.content.Context);
+ method public byte getAnnex();
+ method public long getFec();
+ method public int getModulation();
+ method public int getOuterFec();
+ method public int getSpectralInversion();
+ method public int getSymbolRate();
+ method public int getType();
+ field public static final int ANNEX_A = 1; // 0x1
+ field public static final int ANNEX_B = 2; // 0x2
+ field public static final int ANNEX_C = 4; // 0x4
+ field public static final int ANNEX_UNDEFINED = 0; // 0x0
+ field public static final int MODULATION_AUTO = 1; // 0x1
+ field public static final int MODULATION_MOD_128QAM = 16; // 0x10
+ field public static final int MODULATION_MOD_16QAM = 2; // 0x2
+ field public static final int MODULATION_MOD_256QAM = 32; // 0x20
+ field public static final int MODULATION_MOD_32QAM = 4; // 0x4
+ field public static final int MODULATION_MOD_64QAM = 8; // 0x8
+ field public static final int MODULATION_UNDEFINED = 0; // 0x0
+ field public static final int OUTER_FEC_OUTER_FEC_NONE = 1; // 0x1
+ field public static final int OUTER_FEC_OUTER_FEC_RS = 2; // 0x2
+ field public static final int OUTER_FEC_UNDEFINED = 0; // 0x0
+ field public static final int SPECTRAL_INVERSION_INVERTED = 2; // 0x2
+ field public static final int SPECTRAL_INVERSION_NORMAL = 1; // 0x1
+ field public static final int SPECTRAL_INVERSION_UNDEFINED = 0; // 0x0
+ }
+
+ public static class DvbcFrontendSettings.Builder extends android.media.tv.tuner.frontend.FrontendSettings.Builder<android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder> {
+ method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings build();
+ method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setAnnex(byte);
+ method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setFec(long);
+ method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setModulation(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setOuterFec(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setSpectralInversion(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setSymbolRate(int);
+ }
+
+ public class DvbsCodeRate {
+ method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.frontend.DvbsCodeRate.Builder builder(@NonNull android.content.Context);
+ method public int getBitsPer1000Symbol();
+ method public long getInnerFec();
+ method public boolean isLinear();
+ method public boolean isShortFrameEnabled();
+ }
+
+ public static class DvbsCodeRate.Builder {
+ method @NonNull public android.media.tv.tuner.frontend.DvbsCodeRate build();
+ method @NonNull public android.media.tv.tuner.frontend.DvbsCodeRate.Builder setBitsPer1000Symbol(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbsCodeRate.Builder setInnerFec(long);
+ method @NonNull public android.media.tv.tuner.frontend.DvbsCodeRate.Builder setLinear(boolean);
+ method @NonNull public android.media.tv.tuner.frontend.DvbsCodeRate.Builder setShortFrameEnabled(boolean);
+ }
+
+ public class DvbsFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
+ method public long getInnerFecCapability();
+ method public int getModulationCapability();
+ method public int getStandardCapability();
+ }
+
+ public class DvbsFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
+ method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder builder(@NonNull android.content.Context);
+ method @Nullable public android.media.tv.tuner.frontend.DvbsCodeRate getCodeRate();
+ method public int getInputStreamId();
+ method public int getModulation();
+ method public int getPilot();
+ method public int getRolloff();
+ method public int getStandard();
+ method public int getSymbolRate();
+ method public int getType();
+ method public int getVcmMode();
+ field public static final int MODULATION_AUTO = 1; // 0x1
+ field public static final int MODULATION_MOD_128APSK = 2048; // 0x800
+ field public static final int MODULATION_MOD_16APSK = 256; // 0x100
+ field public static final int MODULATION_MOD_16PSK = 16; // 0x10
+ field public static final int MODULATION_MOD_16QAM = 8; // 0x8
+ field public static final int MODULATION_MOD_256APSK = 4096; // 0x1000
+ field public static final int MODULATION_MOD_32APSK = 512; // 0x200
+ field public static final int MODULATION_MOD_32PSK = 32; // 0x20
+ field public static final int MODULATION_MOD_64APSK = 1024; // 0x400
+ field public static final int MODULATION_MOD_8APSK = 128; // 0x80
+ field public static final int MODULATION_MOD_8PSK = 4; // 0x4
+ field public static final int MODULATION_MOD_ACM = 64; // 0x40
+ field public static final int MODULATION_MOD_QPSK = 2; // 0x2
+ field public static final int MODULATION_MOD_RESERVED = 8192; // 0x2000
+ field public static final int MODULATION_UNDEFINED = 0; // 0x0
+ field public static final int PILOT_AUTO = 3; // 0x3
+ field public static final int PILOT_OFF = 2; // 0x2
+ field public static final int PILOT_ON = 1; // 0x1
+ field public static final int PILOT_UNDEFINED = 0; // 0x0
+ field public static final int ROLLOFF_0_10 = 5; // 0x5
+ field public static final int ROLLOFF_0_15 = 4; // 0x4
+ field public static final int ROLLOFF_0_20 = 3; // 0x3
+ field public static final int ROLLOFF_0_25 = 2; // 0x2
+ field public static final int ROLLOFF_0_35 = 1; // 0x1
+ field public static final int ROLLOFF_0_5 = 6; // 0x6
+ field public static final int ROLLOFF_UNDEFINED = 0; // 0x0
+ field public static final int STANDARD_AUTO = 1; // 0x1
+ field public static final int STANDARD_S = 2; // 0x2
+ field public static final int STANDARD_S2 = 4; // 0x4
+ field public static final int STANDARD_S2X = 8; // 0x8
+ field public static final int VCM_MODE_AUTO = 1; // 0x1
+ field public static final int VCM_MODE_MANUAL = 2; // 0x2
+ field public static final int VCM_MODE_UNDEFINED = 0; // 0x0
+ }
+
+ public static class DvbsFrontendSettings.Builder extends android.media.tv.tuner.frontend.FrontendSettings.Builder<android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder> {
+ method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings build();
+ method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setCodeRate(@Nullable android.media.tv.tuner.frontend.DvbsCodeRate);
+ method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setInputStreamId(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setModulation(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setPilot(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setRolloff(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setStandard(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setSymbolRate(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setVcmMode(int);
+ }
+
+ public class DvbtFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
+ method public int getBandwidthCapability();
+ method public int getCodeRateCapability();
+ method public int getConstellationCapability();
+ method public int getGuardIntervalCapability();
+ method public int getHierarchyCapability();
+ method public int getTransmissionModeCapability();
+ method public boolean isMisoSupported();
+ method public boolean isT2Supported();
+ }
+
+ public class DvbtFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
+ method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder builder(@NonNull android.content.Context);
+ method public int getBandwidth();
+ method public int getConstellation();
+ method public int getGuardInterval();
+ method public int getHierarchy();
+ method public int getHpCodeRate();
+ method public int getLpCodeRate();
+ method public int getPlpGroupId();
+ method public int getPlpId();
+ method public int getPlpMode();
+ method public int getStandard();
+ method public int getTransmissionMode();
+ method public int getType();
+ method public boolean isHighPriority();
+ method public boolean isMiso();
+ field public static final int BANDWIDTH_10MHZ = 64; // 0x40
+ field public static final int BANDWIDTH_1_7MHZ = 32; // 0x20
+ field public static final int BANDWIDTH_5MHZ = 16; // 0x10
+ field public static final int BANDWIDTH_6MHZ = 8; // 0x8
+ field public static final int BANDWIDTH_7MHZ = 4; // 0x4
+ field public static final int BANDWIDTH_8MHZ = 2; // 0x2
+ field public static final int BANDWIDTH_AUTO = 1; // 0x1
+ field public static final int BANDWIDTH_UNDEFINED = 0; // 0x0
+ field public static final int CODERATE_1_2 = 2; // 0x2
+ field public static final int CODERATE_2_3 = 4; // 0x4
+ field public static final int CODERATE_3_4 = 8; // 0x8
+ field public static final int CODERATE_3_5 = 64; // 0x40
+ field public static final int CODERATE_4_5 = 128; // 0x80
+ field public static final int CODERATE_5_6 = 16; // 0x10
+ field public static final int CODERATE_6_7 = 256; // 0x100
+ field public static final int CODERATE_7_8 = 32; // 0x20
+ field public static final int CODERATE_8_9 = 512; // 0x200
+ field public static final int CODERATE_AUTO = 1; // 0x1
+ field public static final int CODERATE_UNDEFINED = 0; // 0x0
+ field public static final int CONSTELLATION_AUTO = 1; // 0x1
+ field public static final int CONSTELLATION_CONSTELLATION_16QAM = 4; // 0x4
+ field public static final int CONSTELLATION_CONSTELLATION_256QAM = 16; // 0x10
+ field public static final int CONSTELLATION_CONSTELLATION_64QAM = 8; // 0x8
+ field public static final int CONSTELLATION_CONSTELLATION_QPSK = 2; // 0x2
+ field public static final int CONSTELLATION_UNDEFINED = 0; // 0x0
+ field public static final int GUARD_INTERVAL_AUTO = 1; // 0x1
+ field public static final int GUARD_INTERVAL_INTERVAL_19_128 = 64; // 0x40
+ field public static final int GUARD_INTERVAL_INTERVAL_19_256 = 128; // 0x80
+ field public static final int GUARD_INTERVAL_INTERVAL_1_128 = 32; // 0x20
+ field public static final int GUARD_INTERVAL_INTERVAL_1_16 = 4; // 0x4
+ field public static final int GUARD_INTERVAL_INTERVAL_1_32 = 2; // 0x2
+ field public static final int GUARD_INTERVAL_INTERVAL_1_4 = 16; // 0x10
+ field public static final int GUARD_INTERVAL_INTERVAL_1_8 = 8; // 0x8
+ field public static final int GUARD_INTERVAL_UNDEFINED = 0; // 0x0
+ field public static final int HIERARCHY_1_INDEPTH = 64; // 0x40
+ field public static final int HIERARCHY_1_NATIVE = 4; // 0x4
+ field public static final int HIERARCHY_2_INDEPTH = 128; // 0x80
+ field public static final int HIERARCHY_2_NATIVE = 8; // 0x8
+ field public static final int HIERARCHY_4_INDEPTH = 256; // 0x100
+ field public static final int HIERARCHY_4_NATIVE = 16; // 0x10
+ field public static final int HIERARCHY_AUTO = 1; // 0x1
+ field public static final int HIERARCHY_NON_INDEPTH = 32; // 0x20
+ field public static final int HIERARCHY_NON_NATIVE = 2; // 0x2
+ field public static final int HIERARCHY_UNDEFINED = 0; // 0x0
+ field public static final int PLP_MODE_AUTO = 1; // 0x1
+ field public static final int PLP_MODE_MANUAL = 2; // 0x2
+ field public static final int PLP_MODE_UNDEFINED = 0; // 0x0
+ field public static final int STANDARD_AUTO = 1; // 0x1
+ field public static final int STANDARD_T = 2; // 0x2
+ field public static final int STANDARD_T2 = 4; // 0x4
+ field public static final int TRANSMISSION_MODE_16K = 32; // 0x20
+ field public static final int TRANSMISSION_MODE_1K = 16; // 0x10
+ field public static final int TRANSMISSION_MODE_2K = 2; // 0x2
+ field public static final int TRANSMISSION_MODE_32K = 64; // 0x40
+ field public static final int TRANSMISSION_MODE_4K = 8; // 0x8
+ field public static final int TRANSMISSION_MODE_8K = 4; // 0x4
+ field public static final int TRANSMISSION_MODE_AUTO = 1; // 0x1
+ field public static final int TRANSMISSION_MODE_UNDEFINED = 0; // 0x0
+ }
+
+ public static class DvbtFrontendSettings.Builder extends android.media.tv.tuner.frontend.FrontendSettings.Builder<android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder> {
+ method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings build();
+ method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setBandwidth(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setConstellation(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setGuardInterval(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setHierarchy(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setHighPriority(boolean);
+ method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setHpCodeRate(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setLpCodeRate(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setMiso(boolean);
+ method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setPlpGroupId(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setPlpId(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setPlpMode(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setStandard(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setTransmissionMode(int);
+ }
+
+ public abstract class FrontendCapabilities {
+ ctor public FrontendCapabilities();
+ }
+
+ public class FrontendInfo {
+ method public int getAcquireRange();
+ method public int getExclusiveGroupId();
+ method @NonNull public android.util.Range<java.lang.Integer> getFrequencyRange();
+ method @NonNull public android.media.tv.tuner.frontend.FrontendCapabilities getFrontendCapability();
+ method public int getId();
+ method @NonNull public int[] getStatusCapabilities();
+ method @NonNull public android.util.Range<java.lang.Integer> getSymbolRateRange();
+ method public int getType();
+ }
+
public abstract class FrontendSettings {
method public int getFrequency();
method public abstract int getType();
+ field public static final long FEC_11_15 = 4194304L; // 0x400000L
+ field public static final long FEC_11_20 = 8388608L; // 0x800000L
+ field public static final long FEC_11_45 = 16777216L; // 0x1000000L
+ field public static final long FEC_13_18 = 33554432L; // 0x2000000L
+ field public static final long FEC_13_45 = 67108864L; // 0x4000000L
+ field public static final long FEC_14_45 = 134217728L; // 0x8000000L
+ field public static final long FEC_1_2 = 2L; // 0x2L
+ field public static final long FEC_1_3 = 4L; // 0x4L
+ field public static final long FEC_1_4 = 8L; // 0x8L
+ field public static final long FEC_1_5 = 16L; // 0x10L
+ field public static final long FEC_23_36 = 268435456L; // 0x10000000L
+ field public static final long FEC_25_36 = 536870912L; // 0x20000000L
+ field public static final long FEC_26_45 = 1073741824L; // 0x40000000L
+ field public static final long FEC_28_45 = -2147483648L; // 0xffffffff80000000L
+ field public static final long FEC_29_45 = 1L; // 0x1L
+ field public static final long FEC_2_3 = 32L; // 0x20L
+ field public static final long FEC_2_5 = 64L; // 0x40L
+ field public static final long FEC_2_9 = 128L; // 0x80L
+ field public static final long FEC_31_45 = 2L; // 0x2L
+ field public static final long FEC_32_45 = 4L; // 0x4L
+ field public static final long FEC_3_4 = 256L; // 0x100L
+ field public static final long FEC_3_5 = 512L; // 0x200L
+ field public static final long FEC_4_15 = 2048L; // 0x800L
+ field public static final long FEC_4_5 = 1024L; // 0x400L
+ field public static final long FEC_5_6 = 4096L; // 0x1000L
+ field public static final long FEC_5_9 = 8192L; // 0x2000L
+ field public static final long FEC_6_7 = 16384L; // 0x4000L
+ field public static final long FEC_77_90 = 8L; // 0x8L
+ field public static final long FEC_7_15 = 131072L; // 0x20000L
+ field public static final long FEC_7_8 = 32768L; // 0x8000L
+ field public static final long FEC_7_9 = 65536L; // 0x10000L
+ field public static final long FEC_8_15 = 524288L; // 0x80000L
+ field public static final long FEC_8_9 = 262144L; // 0x40000L
+ field public static final long FEC_9_10 = 1048576L; // 0x100000L
+ field public static final long FEC_9_20 = 2097152L; // 0x200000L
+ field public static final long FEC_AUTO = 1L; // 0x1L
+ field public static final long FEC_UNDEFINED = 0L; // 0x0L
field public static final int TYPE_ANALOG = 1; // 0x1
field public static final int TYPE_ATSC = 2; // 0x2
field public static final int TYPE_ATSC3 = 3; // 0x3
@@ -5208,6 +5614,200 @@
method @IntRange(from=1) @NonNull public T setFrequency(int);
}
+ public class FrontendStatus {
+ method public int getAgc();
+ method @NonNull public android.media.tv.tuner.frontend.FrontendStatus.Atsc3PlpInfo[] getAtsc3PlpInfo();
+ method public int getBer();
+ method public long getFec();
+ method public int getFreqOffset();
+ method public int getHierarchy();
+ method @NonNull public boolean[] getLayerErrors();
+ method public int getLberCn();
+ method public int getLnbVoltage();
+ method public int getMer();
+ method public int getModulation();
+ method public int getPer();
+ method public int getPerBer();
+ method public int getPlpId();
+ method public int getSignalQuality();
+ method public int getSignalStrength();
+ method public int getSnr();
+ method public int getSpectralInversion();
+ method public int getSymbolRate();
+ method public int getVberCn();
+ method public int getXerCn();
+ method public boolean isDemodLocked();
+ method public boolean isEwbs();
+ method public boolean isLnaOn();
+ method public boolean isRfLock();
+ field public static final int FRONTEND_STATUS_TYPE_AGC = 14; // 0xe
+ field public static final int FRONTEND_STATUS_TYPE_ATSC3_PLP_INFO = 24; // 0x18
+ field public static final int FRONTEND_STATUS_TYPE_BER = 2; // 0x2
+ field public static final int FRONTEND_STATUS_TYPE_DEMOD_LOCK = 0; // 0x0
+ field public static final int FRONTEND_STATUS_TYPE_EWBS = 13; // 0xd
+ field public static final int FRONTEND_STATUS_TYPE_FEC = 8; // 0x8
+ field public static final int FRONTEND_STATUS_TYPE_FREQ_OFFSET = 21; // 0x15
+ field public static final int FRONTEND_STATUS_TYPE_HIERARCHY = 22; // 0x16
+ field public static final int FRONTEND_STATUS_TYPE_LAYER_ERROR = 16; // 0x10
+ field public static final int FRONTEND_STATUS_TYPE_LBER_CN = 18; // 0x12
+ field public static final int FRONTEND_STATUS_TYPE_LNA = 15; // 0xf
+ field public static final int FRONTEND_STATUS_TYPE_LNB_VOLTAGE = 11; // 0xb
+ field public static final int FRONTEND_STATUS_TYPE_MER = 20; // 0x14
+ field public static final int FRONTEND_STATUS_TYPE_MODULATION = 9; // 0x9
+ field public static final int FRONTEND_STATUS_TYPE_PER = 3; // 0x3
+ field public static final int FRONTEND_STATUS_TYPE_PLP_ID = 12; // 0xc
+ field public static final int FRONTEND_STATUS_TYPE_PRE_BER = 4; // 0x4
+ field public static final int FRONTEND_STATUS_TYPE_RF_LOCK = 23; // 0x17
+ field public static final int FRONTEND_STATUS_TYPE_SIGNAL_QUALITY = 5; // 0x5
+ field public static final int FRONTEND_STATUS_TYPE_SIGNAL_STRENGTH = 6; // 0x6
+ field public static final int FRONTEND_STATUS_TYPE_SNR = 1; // 0x1
+ field public static final int FRONTEND_STATUS_TYPE_SPECTRAL = 10; // 0xa
+ field public static final int FRONTEND_STATUS_TYPE_SYMBOL_RATE = 7; // 0x7
+ field public static final int FRONTEND_STATUS_TYPE_VBER_CN = 17; // 0x11
+ field public static final int FRONTEND_STATUS_TYPE_XER_CN = 19; // 0x13
+ }
+
+ public static class FrontendStatus.Atsc3PlpInfo {
+ method public int getPlpId();
+ method public int getUec();
+ method public boolean isLock();
+ }
+
+ public class Isdbs3FrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
+ method public int getCodeRateCapability();
+ method public int getModulationCapability();
+ }
+
+ public class Isdbs3FrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
+ method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder builder(@NonNull android.content.Context);
+ method public int getCodeRate();
+ method public int getModulation();
+ method public int getRolloff();
+ method public int getStreamId();
+ method public int getStreamIdType();
+ method public int getSymbolRate();
+ method public int getType();
+ field public static final int CODERATE_1_2 = 8; // 0x8
+ field public static final int CODERATE_1_3 = 2; // 0x2
+ field public static final int CODERATE_2_3 = 32; // 0x20
+ field public static final int CODERATE_2_5 = 4; // 0x4
+ field public static final int CODERATE_3_4 = 64; // 0x40
+ field public static final int CODERATE_3_5 = 16; // 0x10
+ field public static final int CODERATE_4_5 = 256; // 0x100
+ field public static final int CODERATE_5_6 = 512; // 0x200
+ field public static final int CODERATE_7_8 = 1024; // 0x400
+ field public static final int CODERATE_7_9 = 128; // 0x80
+ field public static final int CODERATE_9_10 = 2048; // 0x800
+ field public static final int CODERATE_AUTO = 1; // 0x1
+ field public static final int CODERATE_UNDEFINED = 0; // 0x0
+ field public static final int MODULATION_AUTO = 1; // 0x1
+ field public static final int MODULATION_MOD_16APSK = 16; // 0x10
+ field public static final int MODULATION_MOD_32APSK = 32; // 0x20
+ field public static final int MODULATION_MOD_8PSK = 8; // 0x8
+ field public static final int MODULATION_MOD_BPSK = 2; // 0x2
+ field public static final int MODULATION_MOD_QPSK = 4; // 0x4
+ field public static final int MODULATION_UNDEFINED = 0; // 0x0
+ field public static final int ROLLOFF_0_03 = 1; // 0x1
+ field public static final int ROLLOFF_UNDEFINED = 0; // 0x0
+ }
+
+ public static class Isdbs3FrontendSettings.Builder extends android.media.tv.tuner.frontend.FrontendSettings.Builder<android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder> {
+ method @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings build();
+ method @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder setCodeRate(int);
+ method @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder setModulation(int);
+ method @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder setRolloff(int);
+ method @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder setStreamId(int);
+ method @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder setStreamIdType(int);
+ method @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder setSymbolRate(int);
+ }
+
+ public class IsdbsFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
+ method public int getCodeRateCapability();
+ method public int getModulationCapability();
+ }
+
+ public class IsdbsFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
+ method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder builder(@NonNull android.content.Context);
+ method public int getCodeRate();
+ method public int getModulation();
+ method public int getRolloff();
+ method public int getStreamId();
+ method public int getStreamIdType();
+ method public int getSymbolRate();
+ method public int getType();
+ field public static final int CODERATE_1_2 = 2; // 0x2
+ field public static final int CODERATE_2_3 = 4; // 0x4
+ field public static final int CODERATE_3_4 = 8; // 0x8
+ field public static final int CODERATE_5_6 = 16; // 0x10
+ field public static final int CODERATE_7_8 = 32; // 0x20
+ field public static final int CODERATE_AUTO = 1; // 0x1
+ field public static final int CODERATE_UNDEFINED = 0; // 0x0
+ field public static final int MODULATION_AUTO = 1; // 0x1
+ field public static final int MODULATION_MOD_BPSK = 2; // 0x2
+ field public static final int MODULATION_MOD_QPSK = 4; // 0x4
+ field public static final int MODULATION_MOD_TC8PSK = 8; // 0x8
+ field public static final int MODULATION_UNDEFINED = 0; // 0x0
+ field public static final int ROLLOFF_0_35 = 1; // 0x1
+ field public static final int ROLLOFF_UNDEFINED = 0; // 0x0
+ field public static final int STREAM_ID_TYPE_ID = 0; // 0x0
+ field public static final int STREAM_ID_TYPE_RELATIVE_NUMBER = 1; // 0x1
+ }
+
+ public static class IsdbsFrontendSettings.Builder extends android.media.tv.tuner.frontend.FrontendSettings.Builder<android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder> {
+ method @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings build();
+ method @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder setCodeRate(int);
+ method @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder setModulation(int);
+ method @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder setRolloff(int);
+ method @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder setStreamId(int);
+ method @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder setStreamIdType(int);
+ method @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder setSymbolRate(int);
+ }
+
+ public class IsdbtFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
+ method public int getBandwidthCapability();
+ method public int getCodeRateCapability();
+ method public int getGuardIntervalCapability();
+ method public int getModeCapability();
+ method public int getModulationCapability();
+ }
+
+ public class IsdbtFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
+ method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder builder(@NonNull android.content.Context);
+ method public int getBandwidth();
+ method public int getCodeRate();
+ method public int getGuardInterval();
+ method public int getMode();
+ method public int getModulation();
+ method public int getServiceAreaId();
+ method public int getType();
+ field public static final int BANDWIDTH_6MHZ = 8; // 0x8
+ field public static final int BANDWIDTH_7MHZ = 4; // 0x4
+ field public static final int BANDWIDTH_8MHZ = 2; // 0x2
+ field public static final int BANDWIDTH_AUTO = 1; // 0x1
+ field public static final int BANDWIDTH_UNDEFINED = 0; // 0x0
+ field public static final int MODE_1 = 2; // 0x2
+ field public static final int MODE_2 = 4; // 0x4
+ field public static final int MODE_3 = 8; // 0x8
+ field public static final int MODE_AUTO = 1; // 0x1
+ field public static final int MODE_UNDEFINED = 0; // 0x0
+ field public static final int MODULATION_AUTO = 1; // 0x1
+ field public static final int MODULATION_MOD_16QAM = 8; // 0x8
+ field public static final int MODULATION_MOD_64QAM = 16; // 0x10
+ field public static final int MODULATION_MOD_DQPSK = 2; // 0x2
+ field public static final int MODULATION_MOD_QPSK = 4; // 0x4
+ field public static final int MODULATION_UNDEFINED = 0; // 0x0
+ }
+
+ public static class IsdbtFrontendSettings.Builder extends android.media.tv.tuner.frontend.FrontendSettings.Builder<android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder> {
+ method @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings build();
+ method @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder setBandwidth(int);
+ method @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder setCodeRate(int);
+ method @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder setGuardInterval(int);
+ method @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder setMode(int);
+ method @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder setModulation(int);
+ method @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder setServiceAreaId(int);
+ }
+
public interface OnTuneEventListener {
method public void onTuneEvent(int);
field public static final int SIGNAL_LOCKED = 0; // 0x0
@@ -7591,7 +8191,7 @@
method @Nullable public android.os.NativeHandle getHandle();
method @NonNull public String getName();
method public long getSize();
- method @NonNull public android.os.NativeHandle releaseHandle();
+ method @Nullable public android.os.NativeHandle releaseHandle();
}
public class HidlSupport {
@@ -10154,6 +10754,19 @@
method @NonNull public java.util.List<android.telephony.CbGeoUtils.LatLng> getVertices();
}
+ public final class CdmaEriInformation implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getEriIconIndex();
+ method public int getEriIconMode();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CdmaEriInformation> CREATOR;
+ field public static final int ERI_FLASH = 2; // 0x2
+ field public static final int ERI_ICON_MODE_FLASH = 1; // 0x1
+ field public static final int ERI_ICON_MODE_NORMAL = 0; // 0x0
+ field public static final int ERI_OFF = 1; // 0x1
+ field public static final int ERI_ON = 0; // 0x0
+ }
+
public class CellBroadcastIntents {
method public static void sendOrderedBroadcastForBackgroundReceivers(@NonNull android.content.Context, @Nullable android.os.UserHandle, @NonNull android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
}
@@ -11179,6 +11792,7 @@
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCarrierPrivilegeStatus(int);
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<java.lang.String> getCarrierPrivilegedPackagesForAllActiveSubscriptions();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules();
+ method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CdmaEriInformation getCdmaEriInformation();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin();
@@ -11328,12 +11942,22 @@
field @Deprecated public static final String EXTRA_APN_TYPE = "apnType";
field public static final String EXTRA_APN_TYPE_INT = "apnTypeInt";
field public static final String EXTRA_DEFAULT_NETWORK_AVAILABLE = "defaultNetworkAvailable";
+ field public static final String EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE = "android.telephony.extra.DEFAULT_SUBSCRIPTION_SELECT_TYPE";
+ field public static final int EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_ALL = 4; // 0x4
+ field public static final int EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DATA = 1; // 0x1
+ field public static final int EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE = 0; // 0x0
+ field public static final int EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_SMS = 3; // 0x3
+ field public static final int EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_VOICE = 2; // 0x2
field public static final String EXTRA_ERROR_CODE = "errorCode";
field public static final String EXTRA_PCO_ID = "pcoId";
field public static final String EXTRA_PCO_VALUE = "pcoValue";
field public static final String EXTRA_PHONE_IN_ECM_STATE = "android.telephony.extra.PHONE_IN_ECM_STATE";
field public static final String EXTRA_PHONE_IN_EMERGENCY_CALL = "android.telephony.extra.PHONE_IN_EMERGENCY_CALL";
field public static final String EXTRA_REDIRECTION_URL = "redirectionUrl";
+ field public static final String EXTRA_SIM_COMBINATION_NAMES = "android.telephony.extra.SIM_COMBINATION_NAMES";
+ field public static final String EXTRA_SIM_COMBINATION_WARNING_TYPE = "android.telephony.extra.SIM_COMBINATION_WARNING_TYPE";
+ field public static final int EXTRA_SIM_COMBINATION_WARNING_TYPE_DUAL_CDMA = 1; // 0x1
+ field public static final int EXTRA_SIM_COMBINATION_WARNING_TYPE_NONE = 0; // 0x0
field public static final String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE";
field public static final String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL";
field public static final String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING";
@@ -11839,7 +12463,8 @@
field public static final String EXTRA_ADDITIONAL_CALL_INFO = "AdditionalCallInfo";
field public static final String EXTRA_ADDITIONAL_SIP_INVITE_FIELDS = "android.telephony.ims.extra.ADDITIONAL_SIP_INVITE_FIELDS";
field public static final String EXTRA_CALL_DISCONNECT_CAUSE = "android.telephony.ims.extra.CALL_DISCONNECT_CAUSE";
- field public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
+ field public static final String EXTRA_CALL_NETWORK_TYPE = "android.telephony.ims.extra.CALL_NETWORK_TYPE";
+ field @Deprecated public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
field public static final String EXTRA_CHILD_NUMBER = "ChildNum";
field public static final String EXTRA_CNA = "cna";
field public static final String EXTRA_CNAP = "cnap";
@@ -11871,8 +12496,8 @@
method public void callSessionConferenceExtendReceived(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
method public void callSessionConferenceExtended(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
method public void callSessionConferenceStateUpdated(android.telephony.ims.ImsConferenceState);
- method public void callSessionHandover(int, int, android.telephony.ims.ImsReasonInfo);
- method public void callSessionHandoverFailed(int, int, android.telephony.ims.ImsReasonInfo);
+ method @Deprecated public void callSessionHandover(int, int, android.telephony.ims.ImsReasonInfo);
+ method @Deprecated public void callSessionHandoverFailed(int, int, android.telephony.ims.ImsReasonInfo);
method public void callSessionHeld(android.telephony.ims.ImsCallProfile);
method public void callSessionHoldFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionHoldReceived(android.telephony.ims.ImsCallProfile);
@@ -11880,7 +12505,7 @@
method public void callSessionInitiatedFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionInviteParticipantsRequestDelivered();
method public void callSessionInviteParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo);
- method public void callSessionMayHandover(int, int);
+ method @Deprecated public void callSessionMayHandover(int, int);
method public void callSessionMergeComplete(android.telephony.ims.stub.ImsCallSessionImplBase);
method public void callSessionMergeFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionMergeStarted(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
@@ -11902,6 +12527,9 @@
method public void callSessionUpdateReceived(android.telephony.ims.ImsCallProfile);
method public void callSessionUpdated(android.telephony.ims.ImsCallProfile);
method public void callSessionUssdMessageReceived(int, String);
+ method public void onHandover(int, int, @Nullable android.telephony.ims.ImsReasonInfo);
+ method public void onHandoverFailed(int, int, @NonNull android.telephony.ims.ImsReasonInfo);
+ method public void onMayHandover(int, int);
}
public final class ImsConferenceState implements android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index 6fb1083..671c87a 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1893,7 +1893,7 @@
method @Nullable public android.os.NativeHandle getHandle();
method @NonNull public String getName();
method public long getSize();
- method @NonNull public android.os.NativeHandle releaseHandle();
+ method @Nullable public android.os.NativeHandle releaseHandle();
}
public abstract class HwBinder implements android.os.IHwBinder {
@@ -3428,7 +3428,8 @@
field public static final String EXTRA_ADDITIONAL_CALL_INFO = "AdditionalCallInfo";
field public static final String EXTRA_ADDITIONAL_SIP_INVITE_FIELDS = "android.telephony.ims.extra.ADDITIONAL_SIP_INVITE_FIELDS";
field public static final String EXTRA_CALL_DISCONNECT_CAUSE = "android.telephony.ims.extra.CALL_DISCONNECT_CAUSE";
- field public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
+ field public static final String EXTRA_CALL_NETWORK_TYPE = "android.telephony.ims.extra.CALL_NETWORK_TYPE";
+ field @Deprecated public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
field public static final String EXTRA_CHILD_NUMBER = "ChildNum";
field public static final String EXTRA_CNA = "cna";
field public static final String EXTRA_CNAP = "cnap";
@@ -3461,8 +3462,8 @@
method public void callSessionConferenceExtendReceived(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
method public void callSessionConferenceExtended(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
method public void callSessionConferenceStateUpdated(android.telephony.ims.ImsConferenceState);
- method public void callSessionHandover(int, int, android.telephony.ims.ImsReasonInfo);
- method public void callSessionHandoverFailed(int, int, android.telephony.ims.ImsReasonInfo);
+ method @Deprecated public void callSessionHandover(int, int, android.telephony.ims.ImsReasonInfo);
+ method @Deprecated public void callSessionHandoverFailed(int, int, android.telephony.ims.ImsReasonInfo);
method public void callSessionHeld(android.telephony.ims.ImsCallProfile);
method public void callSessionHoldFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionHoldReceived(android.telephony.ims.ImsCallProfile);
@@ -3470,7 +3471,7 @@
method public void callSessionInitiatedFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionInviteParticipantsRequestDelivered();
method public void callSessionInviteParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo);
- method public void callSessionMayHandover(int, int);
+ method @Deprecated public void callSessionMayHandover(int, int);
method public void callSessionMergeComplete(android.telephony.ims.stub.ImsCallSessionImplBase);
method public void callSessionMergeFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionMergeStarted(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
@@ -3492,6 +3493,9 @@
method public void callSessionUpdateReceived(android.telephony.ims.ImsCallProfile);
method public void callSessionUpdated(android.telephony.ims.ImsCallProfile);
method public void callSessionUssdMessageReceived(int, String);
+ method public void onHandover(int, int, @Nullable android.telephony.ims.ImsReasonInfo);
+ method public void onHandoverFailed(int, int, @NonNull android.telephony.ims.ImsReasonInfo);
+ method public void onMayHandover(int, int);
}
public final class ImsConferenceState implements android.os.Parcelable {
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index edf0524..16a65e2 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -86,14 +86,6 @@
{{.atomTag = android::util::BATTERY_CYCLE_COUNT},
{.puller = new ResourceHealthManagerPuller(android::util::BATTERY_CYCLE_COUNT)}},
- // ProcStats.
- {{.atomTag = android::util::PROC_STATS},
- {.puller = new StatsCompanionServicePuller(android::util::PROC_STATS)}},
-
- // ProcStatsPkgProc.
- {{.atomTag = android::util::PROC_STATS_PKG_PROC},
- {.puller = new StatsCompanionServicePuller(android::util::PROC_STATS_PKG_PROC)}},
-
// DebugElapsedClock.
{{.atomTag = android::util::DEBUG_ELAPSED_CLOCK},
{.additiveFields = {1, 2, 3, 4},
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 6f63eea..3c4e861 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -8542,13 +8542,16 @@
* Encapsulates the information needed to display a notification as a bubble.
*
* <p>A bubble is used to display app content in a floating window over the existing
- * foreground activity. A bubble has a collapsed state represented by an icon,
- * {@link BubbleMetadata.Builder#setIcon(Icon)} and an expanded state which is populated
- * via {@link BubbleMetadata.Builder#setIntent(PendingIntent)}.</p>
+ * foreground activity. A bubble has a collapsed state represented by an icon and an
+ * expanded state that displays an activity. These may be defined via
+ * {@link BubbleMetadata.Builder#createIntentBubble(PendingIntent, Icon)} or they may
+ * be definied via an existing shortcut using
+ * {@link BubbleMetadata.Builder#createShortcutBubble(String)}.
+ * </p>
*
* <b>Notifications with a valid and allowed bubble will display in collapsed state
* outside of the notification shade on unlocked devices. When a user interacts with the
- * collapsed bubble, the bubble intent will be invoked and displayed.</b>
+ * collapsed bubble, the bubble activity will be invoked and displayed.</b>
*
* @see Notification.Builder#setBubbleMetadata(BubbleMetadata)
*/
@@ -8560,10 +8563,12 @@
private int mDesiredHeight;
@DimenRes private int mDesiredHeightResId;
private int mFlags;
+ private String mShortcutId;
/**
* If set and the app creating the bubble is in the foreground, the bubble will be posted
- * in its expanded state, with the contents of {@link #getIntent()} in a floating window.
+ * in its expanded state, with the contents of {@link #getBubbleIntent()} in a floating
+ * window.
*
* <p>This flag has no effect if the app posting the bubble is not in the foreground.
* The app is considered foreground if it is visible and on the screen, note that
@@ -8595,34 +8600,61 @@
public static final int FLAG_SUPPRESS_NOTIFICATION = 0x00000002;
private BubbleMetadata(PendingIntent expandIntent, PendingIntent deleteIntent,
- Icon icon, int height, @DimenRes int heightResId) {
+ Icon icon, int height, @DimenRes int heightResId, String shortcutId) {
mPendingIntent = expandIntent;
mIcon = icon;
mDesiredHeight = height;
mDesiredHeightResId = heightResId;
mDeleteIntent = deleteIntent;
+ mShortcutId = shortcutId;
}
private BubbleMetadata(Parcel in) {
- mPendingIntent = PendingIntent.CREATOR.createFromParcel(in);
- mIcon = Icon.CREATOR.createFromParcel(in);
+ if (in.readInt() != 0) {
+ mPendingIntent = PendingIntent.CREATOR.createFromParcel(in);
+ }
+ if (in.readInt() != 0) {
+ mIcon = Icon.CREATOR.createFromParcel(in);
+ }
mDesiredHeight = in.readInt();
mFlags = in.readInt();
if (in.readInt() != 0) {
mDeleteIntent = PendingIntent.CREATOR.createFromParcel(in);
}
mDesiredHeightResId = in.readInt();
+ if (in.readInt() != 0) {
+ mShortcutId = in.readString();
+ }
}
/**
- * @return the pending intent used to populate the floating window for this bubble.
+ * @return the shortcut id used to populate the bubble, if it exists.
*/
+ @Nullable
+ public String getShortcutId() {
+ return mShortcutId;
+ }
+
+ /**
+ * @deprecated use {@link #getBubbleIntent()} or use {@link #getShortcutId()} if created
+ * with a valid shortcut instead.
+ */
+ @Deprecated
@NonNull
public PendingIntent getIntent() {
return mPendingIntent;
}
/**
+ * @return the pending intent used to populate the floating window for this bubble, or
+ * null if this bubble is shortcut based.
+ */
+ @Nullable
+ public PendingIntent getBubbleIntent() {
+ return mPendingIntent;
+ }
+
+ /**
* @return the pending intent to send when the bubble is dismissed by a user, if one exists.
*/
@Nullable
@@ -8631,17 +8663,28 @@
}
/**
- * @return the icon that will be displayed for this bubble when it is collapsed.
+ * @deprecated use {@link #getBubbleIcon()} or use {@link #getShortcutId()} if created
+ * with a valid shortcut instead.
*/
+ @Deprecated
@NonNull
public Icon getIcon() {
return mIcon;
}
/**
+ * @return the icon that will be displayed for this bubble when it is collapsed, or null
+ * if the bubble is shortcut based.
+ */
+ @Nullable
+ public Icon getBubbleIcon() {
+ return mIcon;
+ }
+
+ /**
* @return the ideal height, in DPs, for the floating window that app content defined by
- * {@link #getIntent()} for this bubble. A value of 0 indicates a desired height has not
- * been set.
+ * {@link #getBubbleIntent()} for this bubble. A value of 0 indicates a desired height has
+ * not been set.
*/
@Dimension(unit = DP)
public int getDesiredHeight() {
@@ -8650,7 +8693,7 @@
/**
* @return the resId of ideal height for the floating window that app content defined by
- * {@link #getIntent()} for this bubble. A value of 0 indicates a res value has not
+ * {@link #getBubbleIntent()} for this bubble. A value of 0 indicates a res value has not
* been provided for the desired height.
*/
@DimenRes
@@ -8697,8 +8740,14 @@
@Override
public void writeToParcel(Parcel out, int flags) {
- mPendingIntent.writeToParcel(out, 0);
- mIcon.writeToParcel(out, 0);
+ out.writeInt(mPendingIntent != null ? 1 : 0);
+ if (mPendingIntent != null) {
+ mPendingIntent.writeToParcel(out, 0);
+ }
+ out.writeInt(mIcon != null ? 1 : 0);
+ if (mIcon != null) {
+ mIcon.writeToParcel(out, 0);
+ }
out.writeInt(mDesiredHeight);
out.writeInt(mFlags);
out.writeInt(mDeleteIntent != null ? 1 : 0);
@@ -8706,6 +8755,10 @@
mDeleteIntent.writeToParcel(out, 0);
}
out.writeInt(mDesiredHeightResId);
+ out.writeInt(TextUtils.isEmpty(mShortcutId) ? 0 : 1);
+ if (!TextUtils.isEmpty(mShortcutId)) {
+ out.writeString(mShortcutId);
+ }
}
/**
@@ -8733,6 +8786,7 @@
@DimenRes private int mDesiredHeightResId;
private int mFlags;
private PendingIntent mDeleteIntent;
+ private String mShortcutId;
/**
* Constructs a new builder object.
@@ -8741,50 +8795,98 @@
}
/**
- * Sets the intent that will be used when the bubble is expanded. This will display the
- * app content in a floating window over the existing foreground activity.
+ * Creates a {@link BubbleMetadata.Builder} based on a shortcut. Only
+ * {@link android.content.pm.ShortcutManager#addDynamicShortcuts(List)} shortcuts are
+ * supported.
*
- * <p>An intent is required.</p>
+ * <p>The shortcut icon will be used to represent the bubble when it is collapsed.</p>
*
- * @throws IllegalArgumentException if intent is null
+ * <p>The shortcut activity will be used when the bubble is expanded. This will display
+ * the shortcut activity in a floating window over the existing foreground activity.</p>
+ *
+ * <p>If the shortcut has not been published when the bubble notification is sent,
+ * no bubble will be produced. If the shortcut is deleted while the bubble is active,
+ * the bubble will be removed.</p>
+ *
+ * <p>Calling this method will clear the contents of
+ * {@link #createIntentBubble(PendingIntent, Icon)} if it was previously called on
+ * this builder.</p>
*/
@NonNull
- public BubbleMetadata.Builder setIntent(@NonNull PendingIntent intent) {
- if (intent == null) {
- throw new IllegalArgumentException("Bubble requires non-null pending intent");
+ public BubbleMetadata.Builder createShortcutBubble(@NonNull String shortcutId) {
+ if (!TextUtils.isEmpty(shortcutId)) {
+ // If shortcut id is set, we don't use these if they were previously set.
+ mPendingIntent = null;
+ mIcon = null;
}
- mPendingIntent = intent;
+ mShortcutId = shortcutId;
return this;
}
/**
- * Sets the icon that will represent the bubble when it is collapsed.
+ * Creates a {@link BubbleMetadata.Builder} based on the provided intent and icon.
*
- * <p>An icon is required and should be representative of the content within the bubble.
- * If your app produces multiple bubbles, the image should be unique for each of them.
+ * <p>The icon will be used to represent the bubble when it is collapsed. An icon
+ * should be representative of the content within the bubble. If your app produces
+ * multiple bubbles, the icon should be unique for each of them.</p>
+ *
+ * <p>The intent that will be used when the bubble is expanded. This will display the
+ * app content in a floating window over the existing foreground activity.</p>
+ *
+ * <p>Calling this method will clear the contents of
+ * {@link #createShortcutBubble(String)} if it was previously called on this builder.
* </p>
*
- * <p>The shape of a bubble icon is adaptive and will match the device theme.
- *
- * Ideally your icon should be constructed via
- * {@link Icon#createWithAdaptiveBitmap(Bitmap)}, otherwise, the icon will be shrunk
- * and placed on an adaptive shape.
- * </p>
- *
+ * @throws IllegalArgumentException if intent is null.
* @throws IllegalArgumentException if icon is null.
*/
@NonNull
- public BubbleMetadata.Builder setIcon(@NonNull Icon icon) {
+ public BubbleMetadata.Builder createIntentBubble(@NonNull PendingIntent intent,
+ @NonNull Icon icon) {
+ if (intent == null) {
+ throw new IllegalArgumentException("Bubble requires non-null pending intent");
+ }
if (icon == null) {
throw new IllegalArgumentException("Bubbles require non-null icon");
}
+ mShortcutId = null;
+ mPendingIntent = intent;
mIcon = icon;
return this;
}
/**
- * Sets the desired height in DPs for the app content defined by
- * {@link #setIntent(PendingIntent)}.
+ * @deprecated use {@link #createIntentBubble(PendingIntent, Icon)}
+ * or {@link #createShortcutBubble(String)} instead.
+ */
+ @Deprecated
+ @NonNull
+ public BubbleMetadata.Builder setIntent(@NonNull PendingIntent intent) {
+ if (intent == null) {
+ throw new IllegalArgumentException("Bubble requires non-null pending intent");
+ }
+ mShortcutId = null;
+ mPendingIntent = intent;
+ return this;
+ }
+
+ /**
+ * @deprecated use {@link #createIntentBubble(PendingIntent, Icon)}
+ * or {@link #createShortcutBubble(String)} instead.
+ */
+ @Deprecated
+ @NonNull
+ public BubbleMetadata.Builder setIcon(@NonNull Icon icon) {
+ if (icon == null) {
+ throw new IllegalArgumentException("Bubbles require non-null icon");
+ }
+ mShortcutId = null;
+ mIcon = icon;
+ return this;
+ }
+
+ /**
+ * Sets the desired height in DPs for the expanded content of the bubble.
*
* <p>This height may not be respected if there is not enough space on the screen or if
* the provided height is too small to be useful.</p>
@@ -8806,8 +8908,7 @@
/**
- * Sets the desired height via resId for the app content defined by
- * {@link #setIntent(PendingIntent)}.
+ * Sets the desired height via resId for the expanded content of the bubble.
*
* <p>This height may not be respected if there is not enough space on the screen or if
* the provided height is too small to be useful.</p>
@@ -8829,7 +8930,7 @@
/**
* Sets whether the bubble will be posted in its expanded state (with the contents of
- * {@link #getIntent()} in a floating window).
+ * {@link #getBubbleIntent()} in a floating window).
*
* <p>This flag has no effect if the app posting the bubble is not in the foreground.
* The app is considered foreground if it is visible and on the screen, note that
@@ -8882,20 +8983,21 @@
/**
* Creates the {@link BubbleMetadata} defined by this builder.
*
- * @throws IllegalStateException if {@link #setIntent(PendingIntent)} and/or
- * {@link #setIcon(Icon)} have not been called on this
- * builder.
+ * @throws IllegalStateException if neither {@link #createShortcutBubble(String)} or
+ * {@link #createIntentBubble(PendingIntent, Icon)} have been called on this builder.
*/
@NonNull
public BubbleMetadata build() {
- if (mPendingIntent == null) {
- throw new IllegalStateException("Must supply pending intent to bubble");
+ if (mShortcutId == null && mPendingIntent == null) {
+ throw new IllegalStateException(
+ "Must supply pending intent or shortcut to bubble");
}
- if (mIcon == null) {
- throw new IllegalStateException("Must supply an icon for the bubble");
+ if (mShortcutId == null && mIcon == null) {
+ throw new IllegalStateException(
+ "Must supply an icon or shortcut for the bubble");
}
BubbleMetadata data = new BubbleMetadata(mPendingIntent, mDeleteIntent,
- mIcon, mDesiredHeight, mDesiredHeightResId);
+ mIcon, mDesiredHeight, mDesiredHeightResId, mShortcutId);
data.setFlags(mFlags);
return data;
}
diff --git a/core/java/android/app/admin/DevicePolicyKeyguardService.java b/core/java/android/app/admin/DevicePolicyKeyguardService.java
new file mode 100644
index 0000000..c2a76c5
--- /dev/null
+++ b/core/java/android/app/admin/DevicePolicyKeyguardService.java
@@ -0,0 +1,87 @@
+/*
+ * 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.app.admin;
+
+import android.annotation.Nullable;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.SurfaceControl;
+
+/**
+ * Client interface for providing the SystemUI with secondary lockscreen information.
+ *
+ * <p>An implementation must be provided by the device admin app when
+ * {@link DevicePolicyManager#setSecondaryLockscreenEnabled} is set to true and the service must be
+ * declared in the manifest as handling the action
+ * {@link DevicePolicyManager#ACTION_BIND_SECONDARY_LOCKSCREEN_SERVICE}, otherwise the keyguard
+ * will fail to bind to the service and continue to unlock.
+ *
+ * @see DevicePolicyManager#setSecondaryLockscreenEnabled
+ */
+public class DevicePolicyKeyguardService extends Service {
+ private static final String TAG = "DevicePolicyKeyguardService";
+ private IKeyguardCallback mCallback;
+
+ private final IKeyguardClient mClient = new IKeyguardClient.Stub() {
+ @Override
+ public void onSurfaceReady(@Nullable IBinder hostInputToken, IKeyguardCallback callback) {
+ mCallback = callback;
+ SurfaceControl surfaceControl =
+ DevicePolicyKeyguardService.this.onSurfaceReady(hostInputToken);
+
+ if (mCallback != null) {
+ try {
+ mCallback.onSurfaceControlCreated(surfaceControl);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to return created SurfaceControl", e);
+ }
+ }
+ }
+ };
+
+ @Override
+ @Nullable
+ public final IBinder onBind(@Nullable Intent intent) {
+ return mClient.asBinder();
+ }
+
+ /**
+ * Called by keyguard once the host surface for the secondary lockscreen is ready to display
+ * remote content.
+ * @return the {@link SurfaceControl} for the Surface the secondary lockscreen content is
+ * attached to.
+ */
+ @Nullable
+ public SurfaceControl onSurfaceReady(@Nullable IBinder hostInputToken) {
+ return null;
+ }
+
+ /**
+ * Signals to keyguard that the secondary lock screen is ready to be dismissed.
+ */
+ @Nullable
+ public void dismiss() {
+ try {
+ mCallback.onDismiss();
+ } catch (RemoteException e) {
+ Log.e(TAG, "onDismiss failed", e);
+ }
+ }
+}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index a35a899..d58c4eb 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2384,6 +2384,13 @@
public static final int MAX_PASSWORD_LENGTH = 16;
/**
+ * Service Action: Service implemented by a device owner or profile owner to provide a
+ * secondary lockscreen.
+ */
+ public static final String ACTION_BIND_SECONDARY_LOCKSCREEN_SERVICE =
+ "android.app.action.BIND_SECONDARY_LOCKSCREEN_SERVICE";
+
+ /**
* Return true if the given administrator component is currently active (enabled) in the system.
*
* @param admin The administrator component to check for.
@@ -8393,6 +8400,52 @@
}
/**
+ * Called by device owner or profile owner to set whether a secondary lockscreen needs to be
+ * shown.
+ *
+ * <p>The secondary lockscreen will by displayed after the primary keyguard security screen
+ * requirements are met. To provide the lockscreen content the DO/PO will need to provide a
+ * service handling the {@link #ACTION_BIND_SECONDARY_LOCKSCREEN_SERVICE} intent action,
+ * extending the {@link DevicePolicyKeyguardService} class.
+ *
+ * <p>Relevant interactions on the secondary lockscreen should be communicated back to the
+ * keyguard via {@link IKeyguardCallback}, such as when the screen is ready to be dismissed.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param enabled Whether or not the lockscreen needs to be shown.
+ * @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @see #isSecondaryLockscreenEnabled
+ **/
+ public void setSecondaryLockscreenEnabled(@NonNull ComponentName admin, boolean enabled) {
+ throwIfParentInstance("setSecondaryLockscreenEnabled");
+ if (mService != null) {
+ try {
+ mService.setSecondaryLockscreenEnabled(admin, enabled);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Returns whether the secondary lock screen needs to be shown.
+ * @see #setSecondaryLockscreenEnabled
+ * @hide
+ */
+ @SystemApi
+ public boolean isSecondaryLockscreenEnabled(int userId) {
+ throwIfParentInstance("isSecondaryLockscreenEnabled");
+ if (mService != null) {
+ try {
+ return mService.isSecondaryLockscreenEnabled(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
+
+ /**
* Sets which packages may enter lock task mode.
* <p>
* Any packages that share uid with an allowed package will also be allowed to activate lock
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index a2c0856..e7667c0 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -252,6 +252,9 @@
String[] getAccountTypesWithManagementDisabled();
String[] getAccountTypesWithManagementDisabledAsUser(int userId);
+ void setSecondaryLockscreenEnabled(in ComponentName who, boolean enabled);
+ boolean isSecondaryLockscreenEnabled(int userId);
+
void setLockTaskPackages(in ComponentName who, in String[] packages);
String[] getLockTaskPackages(in ComponentName who);
boolean isLockTaskPermitted(in String pkg);
diff --git a/core/java/android/app/admin/IKeyguardCallback.aidl b/core/java/android/app/admin/IKeyguardCallback.aidl
new file mode 100644
index 0000000..81e7d4d
--- /dev/null
+++ b/core/java/android/app/admin/IKeyguardCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.admin;
+
+import android.view.SurfaceControl;
+
+/**
+ * Internal IPC interface for informing the keyguard of events on the secondary lockscreen.
+ * @hide
+ */
+interface IKeyguardCallback {
+ oneway void onSurfaceControlCreated(in SurfaceControl remoteSurfaceControl);
+ oneway void onDismiss();
+}
diff --git a/core/java/android/app/admin/IKeyguardClient.aidl b/core/java/android/app/admin/IKeyguardClient.aidl
new file mode 100644
index 0000000..4bfd990
--- /dev/null
+++ b/core/java/android/app/admin/IKeyguardClient.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.admin;
+
+import android.app.admin.IKeyguardCallback;
+
+/**
+ * Internal IPC interface for a service to provide the SystemUI with secondary lockscreen
+ * information.
+ * @hide
+ */
+interface IKeyguardClient {
+ oneway void onSurfaceReady(in IBinder hostInputToken, in IKeyguardCallback keyguardCallback);
+}
diff --git a/core/java/android/hardware/location/ContextHubClient.java b/core/java/android/hardware/location/ContextHubClient.java
index c6a5dd0..43480ab 100644
--- a/core/java/android/hardware/location/ContextHubClient.java
+++ b/core/java/android/hardware/location/ContextHubClient.java
@@ -136,7 +136,10 @@
* @see NanoAppMessage
* @see ContextHubTransaction.Result
*/
- @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.LOCATION_HARDWARE,
+ android.Manifest.permission.ACCESS_CONTEXT_HUB
+ })
@ContextHubTransaction.Result
public int sendMessageToNanoApp(@NonNull NanoAppMessage message) {
Objects.requireNonNull(message, "NanoAppMessage cannot be null");
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index a51d2c9..1001f80 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -44,7 +44,9 @@
* A class that exposes the Context hubs on a device to applications.
*
* Please note that this class is not expected to be used by unbundled applications. Also, calling
- * applications are expected to have LOCATION_HARDWARE permissions to use this class.
+ * applications are expected to have LOCATION_HARDWARE or ACCESS_CONTEXT_HUB permissions to use this
+ * class. Use of LOCATION_HARDWARE to enable access to these APIs is deprecated and may be removed
+ * in the future - all applications are recommended to move to the ACCESS_CONTEXT_HUB permission.
*
* @hide
*/
@@ -196,7 +198,10 @@
* new APIs.
*/
@Deprecated
- @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.LOCATION_HARDWARE,
+ android.Manifest.permission.ACCESS_CONTEXT_HUB
+ })
public int[] getContextHubHandles() {
try {
return mService.getContextHubHandles();
@@ -217,7 +222,10 @@
* new APIs.
*/
@Deprecated
- @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.LOCATION_HARDWARE,
+ android.Manifest.permission.ACCESS_CONTEXT_HUB
+ })
public ContextHubInfo getContextHubInfo(int hubHandle) {
try {
return mService.getContextHubInfo(hubHandle);
@@ -248,7 +256,10 @@
* @deprecated Use {@link #loadNanoApp(ContextHubInfo, NanoAppBinary)} instead.
*/
@Deprecated
- @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.LOCATION_HARDWARE,
+ android.Manifest.permission.ACCESS_CONTEXT_HUB
+ })
public int loadNanoApp(int hubHandle, @NonNull NanoApp app) {
try {
return mService.loadNanoApp(hubHandle, app);
@@ -275,7 +286,10 @@
* @deprecated Use {@link #unloadNanoApp(ContextHubInfo, long)} instead.
*/
@Deprecated
- @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.LOCATION_HARDWARE,
+ android.Manifest.permission.ACCESS_CONTEXT_HUB
+ })
public int unloadNanoApp(int nanoAppHandle) {
try {
return mService.unloadNanoApp(nanoAppHandle);
@@ -315,7 +329,10 @@
* for loaded nanoapps.
*/
@Deprecated
- @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.LOCATION_HARDWARE,
+ android.Manifest.permission.ACCESS_CONTEXT_HUB
+ })
@Nullable public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppHandle) {
try {
return mService.getNanoAppInstanceInfo(nanoAppHandle);
@@ -338,7 +355,10 @@
* for loaded nanoapps.
*/
@Deprecated
- @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.LOCATION_HARDWARE,
+ android.Manifest.permission.ACCESS_CONTEXT_HUB
+ })
@NonNull public int[] findNanoAppOnHub(int hubHandle, @NonNull NanoAppFilter filter) {
try {
return mService.findNanoAppOnHub(hubHandle, filter);
@@ -373,7 +393,10 @@
* or {@link #createClient(ContextHubInfo, ContextHubClientCallback)}.
*/
@Deprecated
- @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.LOCATION_HARDWARE,
+ android.Manifest.permission.ACCESS_CONTEXT_HUB
+ })
public int sendMessage(int hubHandle, int nanoAppHandle, @NonNull ContextHubMessage message) {
try {
return mService.sendMessage(hubHandle, nanoAppHandle, message);
@@ -389,7 +412,10 @@
*
* @see ContextHubInfo
*/
- @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.LOCATION_HARDWARE,
+ android.Manifest.permission.ACCESS_CONTEXT_HUB
+ })
@NonNull public List<ContextHubInfo> getContextHubs() {
try {
return mService.getContextHubs();
@@ -466,7 +492,10 @@
*
* @see NanoAppBinary
*/
- @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.LOCATION_HARDWARE,
+ android.Manifest.permission.ACCESS_CONTEXT_HUB
+ })
@NonNull public ContextHubTransaction<Void> loadNanoApp(
@NonNull ContextHubInfo hubInfo, @NonNull NanoAppBinary appBinary) {
Objects.requireNonNull(hubInfo, "ContextHubInfo cannot be null");
@@ -495,7 +524,10 @@
*
* @throws NullPointerException if hubInfo is null
*/
- @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.LOCATION_HARDWARE,
+ android.Manifest.permission.ACCESS_CONTEXT_HUB
+ })
@NonNull public ContextHubTransaction<Void> unloadNanoApp(
@NonNull ContextHubInfo hubInfo, long nanoAppId) {
Objects.requireNonNull(hubInfo, "ContextHubInfo cannot be null");
@@ -523,7 +555,10 @@
*
* @throws NullPointerException if hubInfo is null
*/
- @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.LOCATION_HARDWARE,
+ android.Manifest.permission.ACCESS_CONTEXT_HUB
+ })
@NonNull public ContextHubTransaction<Void> enableNanoApp(
@NonNull ContextHubInfo hubInfo, long nanoAppId) {
Objects.requireNonNull(hubInfo, "ContextHubInfo cannot be null");
@@ -551,7 +586,10 @@
*
* @throws NullPointerException if hubInfo is null
*/
- @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.LOCATION_HARDWARE,
+ android.Manifest.permission.ACCESS_CONTEXT_HUB
+ })
@NonNull public ContextHubTransaction<Void> disableNanoApp(
@NonNull ContextHubInfo hubInfo, long nanoAppId) {
Objects.requireNonNull(hubInfo, "ContextHubInfo cannot be null");
@@ -578,7 +616,10 @@
*
* @throws NullPointerException if hubInfo is null
*/
- @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.LOCATION_HARDWARE,
+ android.Manifest.permission.ACCESS_CONTEXT_HUB
+ })
@NonNull public ContextHubTransaction<List<NanoAppState>> queryNanoApps(
@NonNull ContextHubInfo hubInfo) {
Objects.requireNonNull(hubInfo, "ContextHubInfo cannot be null");
@@ -724,7 +765,10 @@
*
* @see ContextHubClientCallback
*/
- @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.LOCATION_HARDWARE,
+ android.Manifest.permission.ACCESS_CONTEXT_HUB
+ })
@NonNull public ContextHubClient createClient(
@NonNull ContextHubInfo hubInfo, @NonNull ContextHubClientCallback callback,
@NonNull @CallbackExecutor Executor executor) {
@@ -761,7 +805,10 @@
*
* @see ContextHubClientCallback
*/
- @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.LOCATION_HARDWARE,
+ android.Manifest.permission.ACCESS_CONTEXT_HUB
+ })
@NonNull public ContextHubClient createClient(
@NonNull ContextHubInfo hubInfo, @NonNull ContextHubClientCallback callback) {
return createClient(hubInfo, callback, new HandlerExecutor(Handler.getMain()));
@@ -780,6 +827,9 @@
* If a client is regenerated, the host endpoint identifier attached to messages sent to the
* nanoapp remains consistent, even if the original process has exited.
*
+ * To avoid unintentionally spreading data from the Context Hub to external applications, it is
+ * strongly recommended that the PendingIntent supplied to this API is an explicit intent.
+ *
* If registered successfully, intents will be delivered regarding events or messages from the
* specified nanoapp from the attached Context Hub. The intent will have an extra
* {@link ContextHubManager.EXTRA_CONTEXT_HUB_INFO} of type {@link ContextHubInfo}, which
@@ -804,7 +854,10 @@
* @throws IllegalStateException if there were too many registered clients at the service
* @throws NullPointerException if pendingIntent or hubInfo is null
*/
- @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.LOCATION_HARDWARE,
+ android.Manifest.permission.ACCESS_CONTEXT_HUB
+ })
@NonNull public ContextHubClient createClient(
@NonNull ContextHubInfo hubInfo, @NonNull PendingIntent pendingIntent, long nanoAppId) {
Objects.requireNonNull(pendingIntent);
diff --git a/core/java/android/os/AppZygote.java b/core/java/android/os/AppZygote.java
index 6daa5b4..9257496 100644
--- a/core/java/android/os/AppZygote.java
+++ b/core/java/android/os/AppZygote.java
@@ -21,6 +21,8 @@
import com.android.internal.annotations.GuardedBy;
+import dalvik.system.VMRuntime;
+
/**
* AppZygote is responsible for interfacing with an application-specific zygote.
*
@@ -113,7 +115,7 @@
"app_zygote", // seInfo
abi, // abi
abi, // acceptedAbiList
- null, // instructionSet
+ VMRuntime.getInstructionSet(abi), // instructionSet
mZygoteUidGidMin,
mZygoteUidGidMax);
diff --git a/core/java/android/os/HidlMemory.java b/core/java/android/os/HidlMemory.java
index aeb6589..02d1e0c 100644
--- a/core/java/android/os/HidlMemory.java
+++ b/core/java/android/os/HidlMemory.java
@@ -85,11 +85,11 @@
}
/**
- * Disowns the underlying handle and returns it. This object becomes invalid.
+ * Disowns the underlying handle and returns it. The underlying handle becomes null.
*
* @return The underlying handle.
*/
- @NonNull
+ @Nullable
public NativeHandle releaseHandle() {
NativeHandle handle = mHandle;
mHandle = null;
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 5d80ab6..c7a8474 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -20,14 +20,20 @@
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
+import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
+import android.system.StructPollfd;
import android.util.Pair;
import android.webkit.WebViewZygote;
import dalvik.system.VMRuntime;
+import libcore.io.IoUtils;
+
+import java.io.FileDescriptor;
import java.util.Map;
+import java.util.concurrent.TimeoutException;
/**
* Tools for managing OS processes.
@@ -487,6 +493,15 @@
private static long sStartElapsedRealtime;
private static long sStartUptimeMillis;
+ private static final int PIDFD_UNKNOWN = 0;
+ private static final int PIDFD_SUPPORTED = 1;
+ private static final int PIDFD_UNSUPPORTED = 2;
+
+ /**
+ * Whether or not the underlying OS supports pidfd
+ */
+ private static int sPidFdSupported = PIDFD_UNKNOWN;
+
/**
* State associated with the zygote process.
* @hide
@@ -1189,4 +1204,90 @@
}
}
+
+ /**
+ * Wait for the death of the given process.
+ *
+ * @param pid The process ID to be waited on
+ * @param timeout The maximum time to wait in milliseconds, or -1 to wait forever
+ * @hide
+ */
+ public static void waitForProcessDeath(int pid, int timeout)
+ throws InterruptedException, TimeoutException {
+ FileDescriptor pidfd = null;
+ if (sPidFdSupported == PIDFD_UNKNOWN) {
+ int fd = -1;
+ try {
+ fd = nativePidFdOpen(pid, 0);
+ sPidFdSupported = PIDFD_SUPPORTED;
+ } catch (ErrnoException e) {
+ sPidFdSupported = e.errno != OsConstants.ENOSYS
+ ? PIDFD_SUPPORTED : PIDFD_UNSUPPORTED;
+ } finally {
+ if (fd >= 0) {
+ pidfd = new FileDescriptor();
+ pidfd.setInt$(fd);
+ }
+ }
+ }
+ boolean fallback = sPidFdSupported == PIDFD_UNSUPPORTED;
+ if (!fallback) {
+ try {
+ if (pidfd == null) {
+ int fd = nativePidFdOpen(pid, 0);
+ if (fd >= 0) {
+ pidfd = new FileDescriptor();
+ pidfd.setInt$(fd);
+ } else {
+ fallback = true;
+ }
+ }
+ if (pidfd != null) {
+ StructPollfd[] fds = new StructPollfd[] {
+ new StructPollfd()
+ };
+ fds[0].fd = pidfd;
+ fds[0].events = (short) OsConstants.POLLIN;
+ fds[0].revents = 0;
+ fds[0].userData = null;
+ int res = Os.poll(fds, timeout);
+ if (res > 0) {
+ return;
+ } else if (res == 0) {
+ throw new TimeoutException();
+ } else {
+ // We should get an ErrnoException now
+ }
+ }
+ } catch (ErrnoException e) {
+ if (e.errno == OsConstants.EINTR) {
+ throw new InterruptedException();
+ }
+ fallback = true;
+ } finally {
+ if (pidfd != null) {
+ IoUtils.closeQuietly(pidfd);
+ }
+ }
+ }
+ if (fallback) {
+ boolean infinity = timeout < 0;
+ long now = System.currentTimeMillis();
+ final long end = now + timeout;
+ while (infinity || now < end) {
+ try {
+ Os.kill(pid, 0);
+ } catch (ErrnoException e) {
+ if (e.errno == OsConstants.ESRCH) {
+ return;
+ }
+ }
+ Thread.sleep(1);
+ now = System.currentTimeMillis();
+ }
+ }
+ throw new TimeoutException();
+ }
+
+ private static native int nativePidFdOpen(int pid, int flags) throws ErrnoException;
}
diff --git a/core/java/android/os/RevocableFileDescriptor.java b/core/java/android/os/RevocableFileDescriptor.java
index a750ce6..ac2cd60 100644
--- a/core/java/android/os/RevocableFileDescriptor.java
+++ b/core/java/android/os/RevocableFileDescriptor.java
@@ -48,6 +48,8 @@
private volatile boolean mRevoked;
+ private ParcelFileDescriptor.OnCloseListener mOnCloseListener;
+
/** {@hide} */
public RevocableFileDescriptor() {
}
@@ -97,6 +99,14 @@
IoUtils.closeQuietly(mInner);
}
+ /**
+ * Callback for indicating that {@link ParcelFileDescriptor} passed to the client
+ * process ({@link #getRevocableFileDescriptor()}) has been closed.
+ */
+ public void addOnCloseListener(ParcelFileDescriptor.OnCloseListener onCloseListener) {
+ mOnCloseListener = onCloseListener;
+ }
+
public boolean isRevoked() {
return mRevoked;
}
@@ -156,6 +166,9 @@
if (DEBUG) Slog.v(TAG, "onRelease()");
mRevoked = true;
IoUtils.closeQuietly(mInner);
+ if (mOnCloseListener != null) {
+ mOnCloseListener.onClose(null);
+ }
}
};
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 513e72f..2732b2e 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -387,7 +387,7 @@
// Specifies whether the cursor control feature set is enabled.
// This can only be true if the text view is editable.
- private final boolean mCursorControlEnabled;
+ private boolean mCursorControlEnabled;
Editor(TextView textView) {
mTextView = textView;
@@ -411,6 +411,16 @@
}
}
+ @VisibleForTesting
+ public void setCursorControlEnabled(boolean enabled) {
+ mCursorControlEnabled = enabled;
+ }
+
+ @VisibleForTesting
+ public boolean getCursorControlEnabled() {
+ return mCursorControlEnabled;
+ }
+
ParcelableParcel saveInstanceState() {
ParcelableParcel state = new ParcelableParcel(getClass().getClassLoader());
Parcel parcel = state.getParcel();
@@ -1204,7 +1214,7 @@
}
// Long press in empty space moves cursor and starts the insertion action mode.
if (!handled && !isPositionOnText(mTouchState.getLastDownX(), mTouchState.getLastDownY())
- && mInsertionControllerEnabled) {
+ && !mTouchState.isOnHandle() && mInsertionControllerEnabled) {
final int offset = mTextView.getOffsetForPosition(mTouchState.getLastDownX(),
mTouchState.getLastDownY());
Selection.setSelection((Spannable) mTextView.getText(), offset);
@@ -5135,6 +5145,37 @@
private float mLastDownRawX, mLastDownRawY;
private Runnable mHider;
+ // Members for fake-dismiss effect in touch through mode.
+ // It is to make InsertionHandleView can receive the MOVE/UP events after calling dismiss(),
+ // which could happen in case of long-press (making selection will dismiss the insertion
+ // handle).
+
+ // Whether the finger is down and hasn't been up yet.
+ private boolean mIsTouchDown = false;
+ // Whether the popup window is in the invisible state and will be dismissed when finger up.
+ private boolean mPendingDismissOnUp = false;
+ // The alpha value of the drawable.
+ private final int mDrawableOpacity = 255;
+
+ // Members for toggling the insertion menu in touch through mode.
+
+ // The coordinate for the touch down event, which is used for transforming the coordinates
+ // of the events to the text view.
+ private float mTouchDownX;
+ private float mTouchDownY;
+ // The cursor offset when touch down. This is to detect whether the cursor is moved when
+ // finger move/up.
+ private int mOffsetDown;
+ // Whether the cursor offset has been changed on the move/up events.
+ private boolean mOffsetChanged;
+ // Whether it is in insertion action mode when finger down.
+ private boolean mIsInActionMode;
+ // The timestamp for the last up event, which is used for double tap detection.
+ private long mLastUpTime;
+ // The text height of the font of the text view, which is used to calculate the Y coordinate
+ // of the touch through events.
+ private float mTextHeight;
+
public InsertionHandleView(Drawable drawable) {
super(drawable, drawable, com.android.internal.R.id.insertion_handle);
}
@@ -5190,6 +5231,11 @@
@Override
public boolean onTouchEvent(MotionEvent ev) {
+ if (mCursorControlEnabled && FLAG_ENABLE_CURSOR_DRAG) {
+ // Should only enable touch through when cursor drag is enabled.
+ // Otherwise the insertion handle view cannot be moved.
+ return touchThrough(ev);
+ }
final boolean result = super.onTouchEvent(ev);
switch (ev.getActionMasked()) {
@@ -5235,6 +5281,115 @@
return result;
}
+ // Handles the touch events in touch through mode.
+ private boolean touchThrough(MotionEvent ev) {
+ final int actionType = ev.getActionMasked();
+ switch (actionType) {
+ case MotionEvent.ACTION_DOWN:
+ mIsTouchDown = true;
+ mOffsetChanged = false;
+ mOffsetDown = mTextView.getSelectionStart();
+ mTouchDownX = ev.getX();
+ mTouchDownY = ev.getY();
+ mIsInActionMode = mTextActionMode != null;
+ if (ev.getEventTime() - mLastUpTime < ViewConfiguration.getDoubleTapTimeout()) {
+ stopTextActionMode(); // Avoid crash when double tap and drag backwards.
+ }
+ final Paint.FontMetrics fontMetrics = mTextView.getPaint().getFontMetrics();
+ mTextHeight = fontMetrics.descent - fontMetrics.ascent;
+ mTouchState.setIsOnHandle(true);
+ break;
+ case MotionEvent.ACTION_UP:
+ mLastUpTime = ev.getEventTime();
+ break;
+ }
+ // Performs the touch through by forward the events to the text view.
+ boolean ret = mTextView.onTouchEvent(transformEventForTouchThrough(ev));
+
+ if (actionType == MotionEvent.ACTION_UP || actionType == MotionEvent.ACTION_CANCEL) {
+ mIsTouchDown = false;
+ if (mPendingDismissOnUp) {
+ dismiss();
+ }
+ mTouchState.setIsOnHandle(false);
+ }
+
+ // Checks for cursor offset change.
+ if (!mOffsetChanged) {
+ int start = mTextView.getSelectionStart();
+ int end = mTextView.getSelectionEnd();
+ if (start != end || mOffsetDown != start) {
+ mOffsetChanged = true;
+ }
+ }
+
+ // Toggling the insertion action mode on finger up.
+ if (!mOffsetChanged && actionType == MotionEvent.ACTION_UP) {
+ if (mIsInActionMode) {
+ stopTextActionMode();
+ } else {
+ startInsertionActionMode();
+ }
+ }
+ return ret;
+ }
+
+ private MotionEvent transformEventForTouchThrough(MotionEvent ev) {
+ // Transforms the touch events to screen coordinates.
+ // And also shift up to make the hit point is on the text.
+ // Note:
+ // - The revised X should reflect the distance to the horizontal center of touch down.
+ // - The revised Y should be at the top of the text.
+ Matrix m = new Matrix();
+ m.setTranslate(ev.getRawX() - ev.getX() + (getMeasuredWidth() >> 1) - mTouchDownX,
+ ev.getRawY() - ev.getY() - mTouchDownY - mTextHeight);
+ ev.transform(m);
+ // Transforms the touch events to text view coordinates.
+ mTextView.toLocalMotionEvent(ev);
+ if (TextView.DEBUG_CURSOR) {
+ logCursor("InsertionHandleView#transformEventForTouchThrough",
+ "Touch through: %d, (%f, %f)",
+ ev.getAction(), ev.getX(), ev.getY());
+ }
+ return ev;
+ }
+
+ @Override
+ public boolean isShowing() {
+ if (mPendingDismissOnUp) {
+ return false;
+ }
+ return super.isShowing();
+ }
+
+ @Override
+ public void show() {
+ super.show();
+ mPendingDismissOnUp = false;
+ mDrawable.setAlpha(mDrawableOpacity);
+ }
+
+ @Override
+ public void dismiss() {
+ if (mIsTouchDown) {
+ if (TextView.DEBUG_CURSOR) {
+ logCursor("InsertionHandleView#dismiss",
+ "Suppressed the real dismiss, only become invisible");
+ }
+ mPendingDismissOnUp = true;
+ mDrawable.setAlpha(0);
+ } else {
+ super.dismiss();
+ mPendingDismissOnUp = false;
+ }
+ }
+
+ @Override
+ protected void updateDrawable(final boolean updateDrawableWhenDragging) {
+ super.updateDrawable(updateDrawableWhenDragging);
+ mDrawable.setAlpha(mDrawableOpacity);
+ }
+
@Override
public int getCurrentCursorOffset() {
return mTextView.getSelectionStart();
@@ -6039,8 +6194,8 @@
eventX, eventY);
// Double tap detection
- if (mTouchState.isMultiTapInSameArea()
- && (isMouse || isPositionOnText(eventX, eventY))) {
+ if (mTouchState.isMultiTapInSameArea() && (isMouse
+ || mTouchState.isOnHandle() || isPositionOnText(eventX, eventY))) {
if (TextView.DEBUG_CURSOR) {
logCursor("SelectionModifierCursorController: onTouchEvent",
"ACTION_DOWN: select and start drag");
diff --git a/core/java/android/widget/EditorTouchState.java b/core/java/android/widget/EditorTouchState.java
index b13ca42..ff3ac073 100644
--- a/core/java/android/widget/EditorTouchState.java
+++ b/core/java/android/widget/EditorTouchState.java
@@ -42,6 +42,7 @@
private long mLastDownMillis;
private float mLastUpX, mLastUpY;
private long mLastUpMillis;
+ private boolean mIsOnHandle;
@IntDef({MultiTapStatus.NONE, MultiTapStatus.FIRST_TAP, MultiTapStatus.DOUBLE_TAP,
MultiTapStatus.TRIPLE_CLICK})
@@ -98,7 +99,15 @@
}
public boolean isDragCloseToVertical() {
- return mIsDragCloseToVertical;
+ return mIsDragCloseToVertical && !mIsOnHandle;
+ }
+
+ public void setIsOnHandle(boolean onHandle) {
+ mIsOnHandle = onHandle;
+ }
+
+ public boolean isOnHandle() {
+ return mIsOnHandle;
}
/**
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index ee6e8c4..89dbca8 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -50,11 +50,14 @@
#include <pwd.h>
#include <signal.h>
#include <string.h>
+#include <sys/epoll.h>
#include <sys/errno.h>
#include <sys/resource.h>
#include <sys/stat.h>
+#include <sys/syscall.h>
#include <sys/sysinfo.h>
#include <sys/types.h>
+#include <time.h>
#include <unistd.h>
#define GUARD_THREAD_PRIORITY 0
@@ -1271,39 +1274,78 @@
return removeAllProcessGroups();
}
+static void throwErrnoException(JNIEnv* env, const char* functionName, int error) {
+ ScopedLocalRef<jstring> detailMessage(env, env->NewStringUTF(functionName));
+ if (detailMessage.get() == NULL) {
+ // Not really much we can do here. We're probably dead in the water,
+ // but let's try to stumble on...
+ env->ExceptionClear();
+ }
+ static jclass errnoExceptionClass =
+ MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/system/ErrnoException"));
+
+ static jmethodID errnoExceptionCtor =
+ GetMethodIDOrDie(env, errnoExceptionClass, "<init>", "(Ljava/lang/String;I)V");
+
+ jobject exception =
+ env->NewObject(errnoExceptionClass, errnoExceptionCtor, detailMessage.get(), error);
+ env->Throw(reinterpret_cast<jthrowable>(exception));
+}
+
+// Wrapper function to the syscall pidfd_open, which creates a file
+// descriptor that refers to the process whose PID is specified in pid.
+static inline int sys_pidfd_open(pid_t pid, unsigned int flags) {
+ return syscall(__NR_pidfd_open, pid, flags);
+}
+
+static jboolean android_os_Process_nativePidFdOpen(JNIEnv* env, jobject, jint pid, jint flags) {
+ int fd = sys_pidfd_open(pid, flags);
+ if (fd < 0) {
+ throwErrnoException(env, "nativePidFdOpen", errno);
+ return -1;
+ }
+ return fd;
+}
+
static const JNINativeMethod methods[] = {
- {"getUidForName", "(Ljava/lang/String;)I", (void*)android_os_Process_getUidForName},
- {"getGidForName", "(Ljava/lang/String;)I", (void*)android_os_Process_getGidForName},
- {"setThreadPriority", "(II)V", (void*)android_os_Process_setThreadPriority},
- {"setThreadScheduler", "(III)V", (void*)android_os_Process_setThreadScheduler},
- {"setCanSelfBackground", "(Z)V", (void*)android_os_Process_setCanSelfBackground},
- {"setThreadPriority", "(I)V", (void*)android_os_Process_setCallingThreadPriority},
- {"getThreadPriority", "(I)I", (void*)android_os_Process_getThreadPriority},
- {"getThreadScheduler", "(I)I", (void*)android_os_Process_getThreadScheduler},
- {"setThreadGroup", "(II)V", (void*)android_os_Process_setThreadGroup},
- {"setThreadGroupAndCpuset", "(II)V", (void*)android_os_Process_setThreadGroupAndCpuset},
- {"setProcessGroup", "(II)V", (void*)android_os_Process_setProcessGroup},
- {"getProcessGroup", "(I)I", (void*)android_os_Process_getProcessGroup},
- {"getExclusiveCores", "()[I", (void*)android_os_Process_getExclusiveCores},
- {"setSwappiness", "(IZ)Z", (void*)android_os_Process_setSwappiness},
- {"setArgV0", "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0},
- {"setUid", "(I)I", (void*)android_os_Process_setUid},
- {"setGid", "(I)I", (void*)android_os_Process_setGid},
- {"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
- {"sendSignalQuiet", "(II)V", (void*)android_os_Process_sendSignalQuiet},
- {"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory},
- {"getTotalMemory", "()J", (void*)android_os_Process_getTotalMemory},
- {"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", (void*)android_os_Process_readProcLines},
- {"getPids", "(Ljava/lang/String;[I)[I", (void*)android_os_Process_getPids},
- {"readProcFile", "(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_readProcFile},
- {"parseProcLine", "([BII[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_parseProcLine},
- {"getElapsedCpuTime", "()J", (void*)android_os_Process_getElapsedCpuTime},
- {"getPss", "(I)J", (void*)android_os_Process_getPss},
- {"getRss", "(I)[J", (void*)android_os_Process_getRss},
- {"getPidsForCommands", "([Ljava/lang/String;)[I", (void*)android_os_Process_getPidsForCommands},
- //{"setApplicationObject", "(Landroid/os/IBinder;)V", (void*)android_os_Process_setApplicationObject},
- {"killProcessGroup", "(II)I", (void*)android_os_Process_killProcessGroup},
- {"removeAllProcessGroups", "()V", (void*)android_os_Process_removeAllProcessGroups},
+ {"getUidForName", "(Ljava/lang/String;)I", (void*)android_os_Process_getUidForName},
+ {"getGidForName", "(Ljava/lang/String;)I", (void*)android_os_Process_getGidForName},
+ {"setThreadPriority", "(II)V", (void*)android_os_Process_setThreadPriority},
+ {"setThreadScheduler", "(III)V", (void*)android_os_Process_setThreadScheduler},
+ {"setCanSelfBackground", "(Z)V", (void*)android_os_Process_setCanSelfBackground},
+ {"setThreadPriority", "(I)V", (void*)android_os_Process_setCallingThreadPriority},
+ {"getThreadPriority", "(I)I", (void*)android_os_Process_getThreadPriority},
+ {"getThreadScheduler", "(I)I", (void*)android_os_Process_getThreadScheduler},
+ {"setThreadGroup", "(II)V", (void*)android_os_Process_setThreadGroup},
+ {"setThreadGroupAndCpuset", "(II)V", (void*)android_os_Process_setThreadGroupAndCpuset},
+ {"setProcessGroup", "(II)V", (void*)android_os_Process_setProcessGroup},
+ {"getProcessGroup", "(I)I", (void*)android_os_Process_getProcessGroup},
+ {"getExclusiveCores", "()[I", (void*)android_os_Process_getExclusiveCores},
+ {"setSwappiness", "(IZ)Z", (void*)android_os_Process_setSwappiness},
+ {"setArgV0", "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0},
+ {"setUid", "(I)I", (void*)android_os_Process_setUid},
+ {"setGid", "(I)I", (void*)android_os_Process_setGid},
+ {"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
+ {"sendSignalQuiet", "(II)V", (void*)android_os_Process_sendSignalQuiet},
+ {"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory},
+ {"getTotalMemory", "()J", (void*)android_os_Process_getTotalMemory},
+ {"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V",
+ (void*)android_os_Process_readProcLines},
+ {"getPids", "(Ljava/lang/String;[I)[I", (void*)android_os_Process_getPids},
+ {"readProcFile", "(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z",
+ (void*)android_os_Process_readProcFile},
+ {"parseProcLine", "([BII[I[Ljava/lang/String;[J[F)Z",
+ (void*)android_os_Process_parseProcLine},
+ {"getElapsedCpuTime", "()J", (void*)android_os_Process_getElapsedCpuTime},
+ {"getPss", "(I)J", (void*)android_os_Process_getPss},
+ {"getRss", "(I)[J", (void*)android_os_Process_getRss},
+ {"getPidsForCommands", "([Ljava/lang/String;)[I",
+ (void*)android_os_Process_getPidsForCommands},
+ //{"setApplicationObject", "(Landroid/os/IBinder;)V",
+ //(void*)android_os_Process_setApplicationObject},
+ {"killProcessGroup", "(II)I", (void*)android_os_Process_killProcessGroup},
+ {"removeAllProcessGroups", "()V", (void*)android_os_Process_removeAllProcessGroups},
+ {"nativePidFdOpen", "(II)I", (void*)android_os_Process_nativePidFdOpen},
};
int register_android_os_Process(JNIEnv* env)
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 2535fcf..4b969ec 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1514,22 +1514,16 @@
DropCapabilitiesBoundingSet(fail_fn);
- bool use_native_bridge = !is_system_server &&
- instruction_set.has_value() &&
- android::NativeBridgeAvailable() &&
- android::NeedsNativeBridge(instruction_set.value().c_str());
+ bool need_pre_initialize_native_bridge =
+ !is_system_server &&
+ instruction_set.has_value() &&
+ android::NativeBridgeAvailable() &&
+ // Native bridge may be already initialized if this
+ // is an app forked from app-zygote.
+ !android::NativeBridgeInitialized() &&
+ android::NeedsNativeBridge(instruction_set.value().c_str());
- if (use_native_bridge && !app_data_dir.has_value()) {
- // The app_data_dir variable should never be empty if we need to use a
- // native bridge. In general, app_data_dir will never be empty for normal
- // applications. It can only happen in special cases (for isolated
- // processes which are not associated with any app). These are launched by
- // the framework and should not be emulated anyway.
- use_native_bridge = false;
- ALOGW("Native bridge will not be used because managed_app_data_dir == nullptr.");
- }
-
- MountEmulatedStorage(uid, mount_external, use_native_bridge, fail_fn);
+ MountEmulatedStorage(uid, mount_external, need_pre_initialize_native_bridge, fail_fn);
// System services, isolated process, webview/app zygote, old target sdk app, should
// give a null in same_uid_pkgs and private_volumes so they don't need app data isolation.
@@ -1555,11 +1549,12 @@
SetGids(env, gids, fail_fn);
SetRLimits(env, rlimits, fail_fn);
- if (use_native_bridge) {
- // Due to the logic behind use_native_bridge we know that both app_data_dir
- // and instruction_set contain values.
- android::PreInitializeNativeBridge(app_data_dir.value().c_str(),
- instruction_set.value().c_str());
+ if (need_pre_initialize_native_bridge) {
+ // Due to the logic behind need_pre_initialize_native_bridge we know that
+ // instruction_set contains a value.
+ android::PreInitializeNativeBridge(
+ app_data_dir.has_value() ? app_data_dir.value().c_str() : nullptr,
+ instruction_set.value().c_str());
}
if (setresgid(gid, gid, gid) == -1) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index da2e078..194e262 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1528,6 +1528,14 @@
android:protectionLevel="signature|privileged" />
<uses-permission android:name="android.permission.LOCATION_HARDWARE"/>
+ <!-- @SystemApi Allows an application to use the Context Hub.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.ACCESS_CONTEXT_HUB"
+ android:protectionLevel="signature|privileged" />
+ <uses-permission android:name="android.permission.ACCESS_CONTEXT_HUB"/>
+
<!-- @SystemApi Allows an application to create mock location providers for testing.
<p>Protection level: signature
@hide
diff --git a/core/res/res/drawable-nodpi/platlogo.xml b/core/res/res/drawable-nodpi/platlogo.xml
index 19a296a..46e8f64 100644
--- a/core/res/res/drawable-nodpi/platlogo.xml
+++ b/core/res/res/drawable-nodpi/platlogo.xml
@@ -1,5 +1,5 @@
<!--
-Copyright (C) 2015 The Android Open Source Project
+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.
@@ -14,14 +14,18 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
+ android:width="240dp"
+ android:height="240dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
<path
- android:fillColor="#FF000000"
- android:pathData="M19.45,22.89l-10.250001,-10.249999l-2.6599998,2.6599998l-1.77,-1.7600002l4.43,-4.4300003l12.0199995,12.0199995l-1.7699986,1.7600002z"/>
+ android:fillColor="#000"
+ android:pathData="M16 4c-2.2 0-4 1.8-4 4v4H4V8c0-2.2 1.8-4 4-4h8z"/>
<path
- android:fillColor="#FF000000"
- android:pathData="M12,6a6,6 0,1 1,-6 6,6 6,0 0,1 6,-6m0,-2.5A8.5,8.5 0,1 0,20.5 12,8.51 8.51,0 0,0 12,3.5Z"/>
+ android:fillColor="#000"
+ android:pathData="M8 20c2.2 0 4-1.8 4-4v-4H4v8h4z"/>
+ <path
+ android:fillColor="#80000000"
+ android:pathData="M16 12c2.2 0 4-1.8 4-4V4h-8v8h4z"/>
</vector>
+
diff --git a/core/res/res/drawable-nodpi/stat_sys_adb.xml b/core/res/res/drawable-nodpi/stat_sys_adb.xml
index 08e9fad..0e9aab2 100644
--- a/core/res/res/drawable-nodpi/stat_sys_adb.xml
+++ b/core/res/res/drawable-nodpi/stat_sys_adb.xml
@@ -1,5 +1,5 @@
<!--
-Copyright (C) 2019 The Android Open Source Project
+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.
@@ -14,17 +14,17 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
<path
- android:fillColor="#FF000000"
- android:pathData="M16.28,16.19A6,6 0,1 0,6 12c0,0.1 0,0.19 0,0.29L9.2,9.11Z"/>
+ android:fillColor="#000"
+ android:pathData="M16 4c-2.2 0-4 1.8-4 4v4H4V8c0-2.2 1.8-4 4-4h8z"/>
<path
- android:fillColor="#FF000000"
- android:pathData="M16,19.48a8.57,8.57 0,1 1,2 -1.52l1.77,1.77a11.07,11.07 0,1 0,-2 1.57Z"/>
+ android:fillColor="#000"
+ android:pathData="M8 20c2.2 0 4-1.8 4-4v-4H4v8h4z"/>
<path
- android:fillColor="#FF000000"
- android:pathData="M12,18a5.77,5.77 0,0 0,2 -0.34l0.19,-0.07 -0.87,-0.87L9.2,12.64 6.82,15A6,6 0,0 0,12 18Z"/>
+ android:fillColor="#80000000"
+ android:pathData="M16 12c2.2 0 4-1.8 4-4V4h-8v8h4z"/>
</vector>
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index fbe4c1a..0c38e71 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -27,9 +27,13 @@
import static android.widget.espresso.TextViewActions.Handle;
import static android.widget.espresso.TextViewActions.clickOnTextAtIndex;
import static android.widget.espresso.TextViewActions.doubleClickOnTextAtIndex;
+import static android.widget.espresso.TextViewActions.doubleTapAndDragHandle;
import static android.widget.espresso.TextViewActions.doubleTapAndDragOnText;
+import static android.widget.espresso.TextViewActions.doubleTapHandle;
import static android.widget.espresso.TextViewActions.dragHandle;
import static android.widget.espresso.TextViewActions.longPressAndDragOnText;
+import static android.widget.espresso.TextViewActions.longPressAndDragHandle;
+import static android.widget.espresso.TextViewActions.longPressHandle;
import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex;
import static android.widget.espresso.TextViewAssertions.doesNotHaveStyledText;
import static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex;
@@ -511,6 +515,111 @@
}
@Test
+ public void testInsertionHandle_touchThrough() {
+ final TextView textView = mActivity.findViewById(R.id.textview);
+ boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled();
+ boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG;
+ textView.getEditorForTesting().setCursorControlEnabled(true);
+ Editor.FLAG_ENABLE_CURSOR_DRAG = true;
+
+ testInsertionHandle();
+ testInsertionHandle_multiLine();
+
+ textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled);
+ Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled;
+ }
+
+ @Test
+ public void testInsertionHandle_longPressToSelect() {
+ // This test only makes sense when Cursor Control flag is enabled.
+ final TextView textView = mActivity.findViewById(R.id.textview);
+ boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled();
+ boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG;
+ textView.getEditorForTesting().setCursorControlEnabled(true);
+ Editor.FLAG_ENABLE_CURSOR_DRAG = true;
+
+ final String text = "hello the world";
+ onView(withId(R.id.textview)).perform(replaceText(text));
+
+ onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
+ onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
+
+ onHandleView(com.android.internal.R.id.insertion_handle).perform(longPressHandle(textView));
+ onView(withId(R.id.textview)).check(hasSelection("world"));
+
+ textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled);
+ Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled;
+ }
+
+ @Test
+ public void testInsertionHandle_longPressAndDragToSelect() {
+ // This test only makes sense when Cursor Control flag is enabled.
+ final TextView textView = mActivity.findViewById(R.id.textview);
+ boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled();
+ boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG;
+ textView.getEditorForTesting().setCursorControlEnabled(true);
+ Editor.FLAG_ENABLE_CURSOR_DRAG = true;
+
+ final String text = "hello the world";
+ onView(withId(R.id.textview)).perform(replaceText(text));
+
+ onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
+ onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
+
+ onHandleView(com.android.internal.R.id.insertion_handle)
+ .perform(longPressAndDragHandle(textView, Handle.INSERTION, text.indexOf('t')));
+ onView(withId(R.id.textview)).check(hasSelection("the world"));
+
+ textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled);
+ Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled;
+ }
+
+ @Test
+ public void testInsertionHandle_doubleTapToSelect() {
+ // This test only makes sense when Cursor Control flag is enabled.
+ final TextView textView = mActivity.findViewById(R.id.textview);
+ boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled();
+ boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG;
+ textView.getEditorForTesting().setCursorControlEnabled(true);
+ Editor.FLAG_ENABLE_CURSOR_DRAG = true;
+
+ final String text = "hello the world";
+ onView(withId(R.id.textview)).perform(replaceText(text));
+
+ onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
+ onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
+
+ onHandleView(com.android.internal.R.id.insertion_handle).perform(doubleTapHandle(textView));
+ onView(withId(R.id.textview)).check(hasSelection("world"));
+
+ textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled);
+ Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled;
+ }
+
+ @Test
+ public void testInsertionHandle_doubleTapAndDragToSelect() {
+ // This test only makes sense when Cursor Control flag is enabled.
+ final TextView textView = mActivity.findViewById(R.id.textview);
+ boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled();
+ boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG;
+ textView.getEditorForTesting().setCursorControlEnabled(true);
+ Editor.FLAG_ENABLE_CURSOR_DRAG = true;
+
+ final String text = "hello the world";
+ onView(withId(R.id.textview)).perform(replaceText(text));
+
+ onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
+ onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
+
+ onHandleView(com.android.internal.R.id.insertion_handle)
+ .perform(doubleTapAndDragHandle(textView, Handle.INSERTION, text.indexOf('t')));
+ onView(withId(R.id.textview)).check(hasSelection("the world"));
+
+ textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled);
+ Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled;
+ }
+
+ @Test
public void testSelectionHandles() {
final String text = "abcd efg hijk lmn";
onView(withId(R.id.textview)).perform(replaceText(text));
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
index 4808a0b..d4c9971 100644
--- a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
@@ -199,6 +199,86 @@
}
/**
+ * Returns an action that long presses then drags on handle from the current position to
+ * endIndex on the TextView.<br>
+ * <br>
+ * View constraints:
+ * <ul>
+ * <li>must be a TextView's drag-handle displayed on screen
+ * <ul>
+ *
+ * @param textView TextView the handle is on
+ * @param handleType Type of the handle
+ * @param endIndex The index of the TextView's text to end the drag at
+ */
+ public static ViewAction longPressAndDragHandle(TextView textView, Handle handleType,
+ int endIndex) {
+ return actionWithAssertions(
+ new DragAction(
+ DragAction.Drag.LONG_PRESS,
+ new CurrentHandleCoordinates(textView),
+ new HandleCoordinates(textView, handleType, endIndex, true),
+ Press.FINGER,
+ Editor.HandleView.class));
+ }
+
+ /**
+ * Returns an action that long presses on the current handle.<br>
+ * <br>
+ * View constraints:
+ * <ul>
+ * <li>must be a TextView's drag-handle displayed on screen
+ * <ul>
+ *
+ * @param textView TextView the handle is on
+ */
+ public static ViewAction longPressHandle(TextView textView) {
+ return actionWithAssertions(
+ new ViewClickAction(Tap.LONG, new CurrentHandleCoordinates(textView),
+ Press.FINGER));
+ }
+
+ /**
+ * Returns an action that double tap then drags on handle from the current position to
+ * endIndex on the TextView.<br>
+ * <br>
+ * View constraints:
+ * <ul>
+ * <li>must be a TextView's drag-handle displayed on screen
+ * <ul>
+ *
+ * @param textView TextView the handle is on
+ * @param handleType Type of the handle
+ * @param endIndex The index of the TextView's text to end the drag at
+ */
+ public static ViewAction doubleTapAndDragHandle(TextView textView, Handle handleType,
+ int endIndex) {
+ return actionWithAssertions(
+ new DragAction(
+ DragAction.Drag.DOUBLE_TAP,
+ new CurrentHandleCoordinates(textView),
+ new HandleCoordinates(textView, handleType, endIndex, true),
+ Press.FINGER,
+ Editor.HandleView.class));
+ }
+
+ /**
+ * Returns an action that double tap on the current handle.<br>
+ * <br>
+ * View constraints:
+ * <ul>
+ * <li>must be a TextView's drag-handle displayed on screen
+ * <ul>
+ *
+ * @param textView TextView the handle is on
+ */
+ public static ViewAction doubleTapHandle(TextView textView) {
+ return actionWithAssertions(
+ new ViewClickAction(Tap.DOUBLE, new CurrentHandleCoordinates(textView),
+ Press.FINGER));
+ }
+
+ /**
* Returns an action that double taps then drags on text from startIndex to endIndex on the
* TextView.<br>
* <br>
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 62ab2c9..bac425b 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -23,6 +23,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.Context;
+import android.media.tv.TvInputService;
import android.media.tv.tuner.TunerConstants.Result;
import android.media.tv.tuner.dvr.DvrPlayback;
import android.media.tv.tuner.dvr.DvrRecorder;
@@ -55,7 +56,7 @@
* @hide
*/
@SystemApi
-public final class Tuner implements AutoCloseable {
+public class Tuner implements AutoCloseable {
private static final String TAG = "MediaTvTuner";
private static final boolean DEBUG = false;
@@ -88,25 +89,13 @@
/**
* Constructs a Tuner instance.
*
- * @param context context of the caller.
- */
- public Tuner(@NonNull Context context) {
- mContext = context;
- nativeSetup();
- }
-
- /**
- * Constructs a Tuner instance.
- *
* @param context the context of the caller.
* @param tvInputSessionId the session ID of the TV input.
* @param useCase the use case of this Tuner instance.
- *
- * @hide
- * TODO: replace the other constructor
*/
@RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
- public Tuner(@NonNull Context context, @NonNull String tvInputSessionId, int useCase,
+ public Tuner(@NonNull Context context, @NonNull String tvInputSessionId,
+ @TvInputService.PriorityHintUseCaseType int useCase,
@Nullable OnResourceLostListener listener) {
mContext = context;
}
@@ -115,18 +104,21 @@
* Shares the frontend resource with another Tuner instance
*
* @param tuner the Tuner instance to share frontend resource with.
- *
- * @hide
*/
public void shareFrontendFromTuner(@NonNull Tuner tuner) {
+ // TODO: implementation.
}
private long mNativeContext; // used by native jMediaTuner
- /** @hide */
+ /**
+ * Releases the Tuner instance.
+ */
@Override
- public void close() {}
+ public void close() {
+ // TODO: implementation.
+ }
/**
* Native Initialization.
@@ -176,7 +168,7 @@
/**
* Listener for resource lost.
*
- * @hide
+ * <p>Resource is reclaimed and tuner instance is forced to close.
*/
public interface OnResourceLostListener {
/**
@@ -269,8 +261,8 @@
* start a new tuning.
*
* <p>
- * Tune is an async call, with {@link OnTuneEventListener#LOCKED LOCKED} and {@link
- * OnTuneEventListener#NO_SIGNAL NO_SIGNAL} events sent to the {@link OnTuneEventListener}
+ * Tune is an async call, with {@link OnTuneEventListener#SIGNAL_LOCKED} and {@link
+ * OnTuneEventListener#SIGNAL_NO_SIGNAL} events sent to the {@link OnTuneEventListener}
* specified in {@link #setOnTuneEventListener(Executor, OnTuneEventListener)}.
*
* @param settings Signal delivery information the frontend uses to
@@ -357,13 +349,9 @@
* @param lnb the LNB instance.
*
* @return result status of the operation.
- *
- * @hide
*/
- @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
@Result
- public int setLnb(@NonNull Lnb lnb) {
- TunerUtils.checkTunerPermission(mContext);
+ private int setLnb(@NonNull Lnb lnb) {
return nativeSetLnb(lnb.mId);
}
@@ -373,8 +361,6 @@
* @param enable {@code true} to activate LNA module; {@code false} to deactivate LNA.
*
* @return result status of the operation.
- *
- * @hide
*/
@RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
@Result
@@ -390,10 +376,9 @@
*
* @param statusTypes an array of status types which the caller requests.
* @return statuses which response the caller's requests.
- * @hide
*/
@Nullable
- public FrontendStatus getFrontendStatus(int[] statusTypes) {
+ public FrontendStatus getFrontendStatus(@NonNull int[] statusTypes) {
return nativeGetFrontendStatus(statusTypes);
}
@@ -402,8 +387,6 @@
*
* @param filter the filter instance for the hardware sync ID.
* @return the id of hardware A/V sync.
- *
- * @hide
*/
@RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
public int getAvSyncHwId(@NonNull Filter filter) {
@@ -419,8 +402,6 @@
*
* @param avSyncHwId the hardware id of A/V sync.
* @return the current timestamp of hardware A/V sync.
- *
- * @hide
*/
@RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
public long getAvSyncTime(int avSyncHwId) {
@@ -436,8 +417,6 @@
*
* @param ciCamId specify CI-CAM Id to connect.
* @return result status of the operation.
- *
- * @hide
*/
@RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
@Result
@@ -452,8 +431,6 @@
* <p>The demux will use the output from the frontend as the input after this call.
*
* @return result status of the operation.
- *
- * @hide
*/
@RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
@Result
@@ -466,8 +443,6 @@
* Gets the frontend information.
*
* @return The frontend information. {@code null} if the operation failed.
- *
- * @hide
*/
@RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
@Nullable
@@ -480,23 +455,7 @@
}
/**
- * Gets the frontend ID.
- *
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
- public int getFrontendId() {
- TunerUtils.checkTunerPermission(mContext);
- if (mFrontend == null) {
- throw new IllegalStateException("frontend is not initialized");
- }
- return mFrontend.mId;
- }
-
- /**
* Gets Demux capabilities.
- *
- * @hide
*/
@RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
@Nullable
@@ -622,19 +581,6 @@
}
/**
- * This class is used to interact with descramblers.
- *
- * <p> Descrambler is a hardware component used to descramble data.
- *
- * <p> This class controls the TIS interaction with Tuner HAL.
- * TODO: Remove
- */
- public class Descrambler {
- private Descrambler() {
- }
- }
-
- /**
* Opens a Descrambler in tuner.
*
* @return a {@link Descrambler} object.
diff --git a/media/java/android/media/tv/tuner/TunerConstants.java b/media/java/android/media/tv/tuner/TunerConstants.java
index c030619..f54808d 100644
--- a/media/java/android/media/tv/tuner/TunerConstants.java
+++ b/media/java/android/media/tv/tuner/TunerConstants.java
@@ -17,14 +17,8 @@
package android.media.tv.tuner;
import android.annotation.IntDef;
-import android.annotation.LongDef;
import android.annotation.SystemApi;
import android.hardware.tv.tuner.V1_0.Constants;
-import android.media.tv.tuner.frontend.DvbcFrontendSettings;
-import android.media.tv.tuner.frontend.DvbsFrontendSettings;
-import android.media.tv.tuner.frontend.Isdbs3FrontendSettings;
-import android.media.tv.tuner.frontend.IsdbsFrontendSettings;
-import android.media.tv.tuner.frontend.IsdbtFrontendSettings;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -38,12 +32,10 @@
public final class TunerConstants {
/**
* Invalid TS packet ID.
- * @hide
*/
public static final int INVALID_TS_PID = Constants.Constant.INVALID_TS_PID;
/**
* Invalid stream ID.
- * @hide
*/
public static final int INVALID_STREAM_ID = Constants.Constant.INVALID_STREAM_ID;
@@ -58,7 +50,7 @@
/**
* Scan type auto.
*
- * <p> Tuner will send {@link #onLocked}
+ * <p> Tuner will send {@link android.media.tv.tuner.frontend.ScanCallback#onLocked}
*/
public static final int SCAN_TYPE_AUTO = Constants.FrontendScanType.SCAN_AUTO;
/**
@@ -70,350 +62,6 @@
public static final int SCAN_TYPE_BLIND = Constants.FrontendScanType.SCAN_BLIND;
/** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = "INDEX_TYPE_", value =
- {INDEX_TYPE_NONE, INDEX_TYPE_SC, INDEX_TYPE_SC_HEVC})
- public @interface ScIndexType {}
-
- /**
- * Start Code Index is not used.
- * @hide
- */
- public static final int INDEX_TYPE_NONE = Constants.DemuxRecordScIndexType.NONE;
- /**
- * Start Code index.
- * @hide
- */
- public static final int INDEX_TYPE_SC = Constants.DemuxRecordScIndexType.SC;
- /**
- * Start Code index for HEVC.
- * @hide
- */
- public static final int INDEX_TYPE_SC_HEVC = Constants.DemuxRecordScIndexType.SC_HEVC;
-
- /**
- * Indexes can be tagged by Start Code in PES (Packetized Elementary Stream)
- * according to ISO/IEC 13818-1.
- * @hide
- */
- @IntDef(flag = true, value = {SC_INDEX_I_FRAME, SC_INDEX_P_FRAME, SC_INDEX_B_FRAME,
- SC_INDEX_SEQUENCE})
- @Retention(RetentionPolicy.SOURCE)
- public @interface ScIndex {}
-
- /**
- * SC index for a new I-frame.
- */
- public static final int SC_INDEX_I_FRAME = Constants.DemuxScIndex.I_FRAME;
- /**
- * SC index for a new P-frame.
- */
- public static final int SC_INDEX_P_FRAME = Constants.DemuxScIndex.P_FRAME;
- /**
- * SC index for a new B-frame.
- */
- public static final int SC_INDEX_B_FRAME = Constants.DemuxScIndex.B_FRAME;
- /**
- * SC index for a new sequence.
- */
- public static final int SC_INDEX_SEQUENCE = Constants.DemuxScIndex.SEQUENCE;
-
-
- /**
- * Indexes can be tagged by NAL unit group in HEVC according to ISO/IEC 23008-2.
- *
- * @hide
- */
- @IntDef(flag = true,
- value = {SC_HEVC_INDEX_SPS, SC_HEVC_INDEX_AUD, SC_HEVC_INDEX_SLICE_CE_BLA_W_LP,
- SC_HEVC_INDEX_SLICE_BLA_W_RADL, SC_HEVC_INDEX_SLICE_BLA_N_LP,
- SC_HEVC_INDEX_SLICE_IDR_W_RADL, SC_HEVC_INDEX_SLICE_IDR_N_LP,
- SC_HEVC_INDEX_SLICE_TRAIL_CRA})
- @Retention(RetentionPolicy.SOURCE)
- public @interface ScHevcIndex {}
-
- /**
- * SC HEVC index SPS.
- */
- public static final int SC_HEVC_INDEX_SPS = Constants.DemuxScHevcIndex.SPS;
- /**
- * SC HEVC index AUD.
- */
- public static final int SC_HEVC_INDEX_AUD = Constants.DemuxScHevcIndex.AUD;
- /**
- * SC HEVC index SLICE_CE_BLA_W_LP.
- */
- public static final int SC_HEVC_INDEX_SLICE_CE_BLA_W_LP =
- Constants.DemuxScHevcIndex.SLICE_CE_BLA_W_LP;
- /**
- * SC HEVC index SLICE_BLA_W_RADL.
- */
- public static final int SC_HEVC_INDEX_SLICE_BLA_W_RADL =
- Constants.DemuxScHevcIndex.SLICE_BLA_W_RADL;
- /**
- * SC HEVC index SLICE_BLA_N_LP.
- */
- public static final int SC_HEVC_INDEX_SLICE_BLA_N_LP =
- Constants.DemuxScHevcIndex.SLICE_BLA_N_LP;
- /**
- * SC HEVC index SLICE_IDR_W_RADL.
- */
- public static final int SC_HEVC_INDEX_SLICE_IDR_W_RADL =
- Constants.DemuxScHevcIndex.SLICE_IDR_W_RADL;
- /**
- * SC HEVC index SLICE_IDR_N_LP.
- */
- public static final int SC_HEVC_INDEX_SLICE_IDR_N_LP =
- Constants.DemuxScHevcIndex.SLICE_IDR_N_LP;
- /**
- * SC HEVC index SLICE_TRAIL_CRA.
- */
- public static final int SC_HEVC_INDEX_SLICE_TRAIL_CRA =
- Constants.DemuxScHevcIndex.SLICE_TRAIL_CRA;
-
- /** @hide */
- @LongDef({FEC_UNDEFINED, FEC_AUTO, FEC_1_2, FEC_1_3, FEC_1_4, FEC_1_5, FEC_2_3, FEC_2_5,
- FEC_2_9, FEC_3_4, FEC_3_5, FEC_4_5, FEC_4_15, FEC_5_6, FEC_5_9, FEC_6_7, FEC_7_8,
- FEC_7_9, FEC_7_15, FEC_8_9, FEC_8_15, FEC_9_10, FEC_9_20, FEC_11_15, FEC_11_20,
- FEC_11_45, FEC_13_18, FEC_13_45, FEC_14_45, FEC_23_36, FEC_25_36, FEC_26_45, FEC_28_45,
- FEC_29_45, FEC_31_45, FEC_32_45, FEC_77_90})
- @Retention(RetentionPolicy.SOURCE)
- public @interface FrontendInnerFec {}
-
- /**
- * FEC not defined
- * @hide
- */
- public static final long FEC_UNDEFINED = Constants.FrontendInnerFec.FEC_UNDEFINED;
- /**
- * hardware is able to detect and set FEC automatically
- * @hide
- */
- public static final long FEC_AUTO = Constants.FrontendInnerFec.AUTO;
- /**
- * 1/2 conv. code rate
- * @hide
- */
- public static final long FEC_1_2 = Constants.FrontendInnerFec.FEC_1_2;
- /**
- * 1/3 conv. code rate
- * @hide
- */
- public static final long FEC_1_3 = Constants.FrontendInnerFec.FEC_1_3;
- /**
- * 1/4 conv. code rate
- * @hide
- */
- public static final long FEC_1_4 = Constants.FrontendInnerFec.FEC_1_4;
- /**
- * 1/5 conv. code rate
- * @hide
- */
- public static final long FEC_1_5 = Constants.FrontendInnerFec.FEC_1_5;
- /**
- * 2/3 conv. code rate
- * @hide
- */
- public static final long FEC_2_3 = Constants.FrontendInnerFec.FEC_2_3;
- /**
- * 2/5 conv. code rate
- * @hide
- */
- public static final long FEC_2_5 = Constants.FrontendInnerFec.FEC_2_5;
- /**
- * 2/9 conv. code rate
- * @hide
- */
- public static final long FEC_2_9 = Constants.FrontendInnerFec.FEC_2_9;
- /**
- * 3/4 conv. code rate
- * @hide
- */
- public static final long FEC_3_4 = Constants.FrontendInnerFec.FEC_3_4;
- /**
- * 3/5 conv. code rate
- * @hide
- */
- public static final long FEC_3_5 = Constants.FrontendInnerFec.FEC_3_5;
- /**
- * 4/5 conv. code rate
- * @hide
- */
- public static final long FEC_4_5 = Constants.FrontendInnerFec.FEC_4_5;
- /**
- * 4/15 conv. code rate
- * @hide
- */
- public static final long FEC_4_15 = Constants.FrontendInnerFec.FEC_4_15;
- /**
- * 5/6 conv. code rate
- * @hide
- */
- public static final long FEC_5_6 = Constants.FrontendInnerFec.FEC_5_6;
- /**
- * 5/9 conv. code rate
- * @hide
- */
- public static final long FEC_5_9 = Constants.FrontendInnerFec.FEC_5_9;
- /**
- * 6/7 conv. code rate
- * @hide
- */
- public static final long FEC_6_7 = Constants.FrontendInnerFec.FEC_6_7;
- /**
- * 7/8 conv. code rate
- * @hide
- */
- public static final long FEC_7_8 = Constants.FrontendInnerFec.FEC_7_8;
- /**
- * 7/9 conv. code rate
- * @hide
- */
- public static final long FEC_7_9 = Constants.FrontendInnerFec.FEC_7_9;
- /**
- * 7/15 conv. code rate
- * @hide
- */
- public static final long FEC_7_15 = Constants.FrontendInnerFec.FEC_7_15;
- /**
- * 8/9 conv. code rate
- * @hide
- */
- public static final long FEC_8_9 = Constants.FrontendInnerFec.FEC_8_9;
- /**
- * 8/15 conv. code rate
- * @hide
- */
- public static final long FEC_8_15 = Constants.FrontendInnerFec.FEC_8_15;
- /**
- * 9/10 conv. code rate
- * @hide
- */
- public static final long FEC_9_10 = Constants.FrontendInnerFec.FEC_9_10;
- /**
- * 9/20 conv. code rate
- * @hide
- */
- public static final long FEC_9_20 = Constants.FrontendInnerFec.FEC_9_20;
- /**
- * 11/15 conv. code rate
- * @hide
- */
- public static final long FEC_11_15 = Constants.FrontendInnerFec.FEC_11_15;
- /**
- * 11/20 conv. code rate
- * @hide
- */
- public static final long FEC_11_20 = Constants.FrontendInnerFec.FEC_11_20;
- /**
- * 11/45 conv. code rate
- * @hide
- */
- public static final long FEC_11_45 = Constants.FrontendInnerFec.FEC_11_45;
- /**
- * 13/18 conv. code rate
- * @hide
- */
- public static final long FEC_13_18 = Constants.FrontendInnerFec.FEC_13_18;
- /**
- * 13/45 conv. code rate
- * @hide
- */
- public static final long FEC_13_45 = Constants.FrontendInnerFec.FEC_13_45;
- /**
- * 14/45 conv. code rate
- * @hide
- */
- public static final long FEC_14_45 = Constants.FrontendInnerFec.FEC_14_45;
- /**
- * 23/36 conv. code rate
- * @hide
- */
- public static final long FEC_23_36 = Constants.FrontendInnerFec.FEC_23_36;
- /**
- * 25/36 conv. code rate
- * @hide
- */
- public static final long FEC_25_36 = Constants.FrontendInnerFec.FEC_25_36;
- /**
- * 26/45 conv. code rate
- * @hide
- */
- public static final long FEC_26_45 = Constants.FrontendInnerFec.FEC_26_45;
- /**
- * 28/45 conv. code rate
- * @hide
- */
- public static final long FEC_28_45 = Constants.FrontendInnerFec.FEC_28_45;
- /**
- * 29/45 conv. code rate
- * @hide
- */
- public static final long FEC_29_45 = Constants.FrontendInnerFec.FEC_29_45;
- /**
- * 31/45 conv. code rate
- * @hide
- */
- public static final long FEC_31_45 = Constants.FrontendInnerFec.FEC_31_45;
- /**
- * 32/45 conv. code rate
- * @hide
- */
- public static final long FEC_32_45 = Constants.FrontendInnerFec.FEC_32_45;
- /**
- * 77/90 conv. code rate
- * @hide
- */
- public static final long FEC_77_90 = Constants.FrontendInnerFec.FEC_77_90;
-
-
- /** @hide */
- @IntDef(value = {
- DvbcFrontendSettings.MODULATION_UNDEFINED,
- DvbcFrontendSettings.MODULATION_AUTO,
- DvbcFrontendSettings.MODULATION_MOD_16QAM,
- DvbcFrontendSettings.MODULATION_MOD_32QAM,
- DvbcFrontendSettings.MODULATION_MOD_64QAM,
- DvbcFrontendSettings.MODULATION_MOD_128QAM,
- DvbcFrontendSettings.MODULATION_MOD_256QAM,
- DvbsFrontendSettings.MODULATION_UNDEFINED,
- DvbsFrontendSettings.MODULATION_AUTO,
- DvbsFrontendSettings.MODULATION_MOD_QPSK,
- DvbsFrontendSettings.MODULATION_MOD_8PSK,
- DvbsFrontendSettings.MODULATION_MOD_16QAM,
- DvbsFrontendSettings.MODULATION_MOD_16PSK,
- DvbsFrontendSettings.MODULATION_MOD_32PSK,
- DvbsFrontendSettings.MODULATION_MOD_ACM,
- DvbsFrontendSettings.MODULATION_MOD_8APSK,
- DvbsFrontendSettings.MODULATION_MOD_16APSK,
- DvbsFrontendSettings.MODULATION_MOD_32APSK,
- DvbsFrontendSettings.MODULATION_MOD_64APSK,
- DvbsFrontendSettings.MODULATION_MOD_128APSK,
- DvbsFrontendSettings.MODULATION_MOD_256APSK,
- DvbsFrontendSettings.MODULATION_MOD_RESERVED,
- IsdbsFrontendSettings.MODULATION_UNDEFINED,
- IsdbsFrontendSettings.MODULATION_AUTO,
- IsdbsFrontendSettings.MODULATION_MOD_BPSK,
- IsdbsFrontendSettings.MODULATION_MOD_QPSK,
- IsdbsFrontendSettings.MODULATION_MOD_TC8PSK,
- Isdbs3FrontendSettings.MODULATION_UNDEFINED,
- Isdbs3FrontendSettings.MODULATION_AUTO,
- Isdbs3FrontendSettings.MODULATION_MOD_BPSK,
- Isdbs3FrontendSettings.MODULATION_MOD_QPSK,
- Isdbs3FrontendSettings.MODULATION_MOD_8PSK,
- Isdbs3FrontendSettings.MODULATION_MOD_16APSK,
- Isdbs3FrontendSettings.MODULATION_MOD_32APSK,
- IsdbtFrontendSettings.MODULATION_UNDEFINED,
- IsdbtFrontendSettings.MODULATION_AUTO,
- IsdbtFrontendSettings.MODULATION_MOD_DQPSK,
- IsdbtFrontendSettings.MODULATION_MOD_QPSK,
- IsdbtFrontendSettings.MODULATION_MOD_16QAM,
- IsdbtFrontendSettings.MODULATION_MOD_64QAM})
- @Retention(RetentionPolicy.SOURCE)
- public @interface FrontendModulation {}
-
-
- /** @hide */
@IntDef({RESULT_SUCCESS, RESULT_UNAVAILABLE, RESULT_NOT_INITIALIZED, RESULT_INVALID_STATE,
RESULT_INVALID_ARGUMENT, RESULT_OUT_OF_MEMORY, RESULT_UNKNOWN_ERROR})
@Retention(RetentionPolicy.SOURCE)
diff --git a/media/java/android/media/tv/tuner/filter/RecordSettings.java b/media/java/android/media/tv/tuner/filter/RecordSettings.java
index 209ed67..0c812ab 100644
--- a/media/java/android/media/tv/tuner/filter/RecordSettings.java
+++ b/media/java/android/media/tv/tuner/filter/RecordSettings.java
@@ -22,8 +22,6 @@
import android.annotation.SystemApi;
import android.content.Context;
import android.hardware.tv.tuner.V1_0.Constants;
-import android.media.tv.tuner.TunerConstants;
-import android.media.tv.tuner.TunerConstants.ScIndexType;
import android.media.tv.tuner.TunerUtils;
import java.lang.annotation.Retention;
@@ -112,29 +110,130 @@
*/
public static final int TS_INDEX_ADAPTATION_EXTENSION_FLAG =
Constants.DemuxTsIndex.ADAPTATION_EXTENSION_FLAG;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "INDEX_TYPE_", value =
+ {INDEX_TYPE_NONE, INDEX_TYPE_SC, INDEX_TYPE_SC_HEVC})
+ public @interface ScIndexType {}
+
+ /**
+ * Start Code Index is not used.
+ */
+ public static final int INDEX_TYPE_NONE = Constants.DemuxRecordScIndexType.NONE;
+ /**
+ * Start Code index.
+ */
+ public static final int INDEX_TYPE_SC = Constants.DemuxRecordScIndexType.SC;
+ /**
+ * Start Code index for HEVC.
+ */
+ public static final int INDEX_TYPE_SC_HEVC = Constants.DemuxRecordScIndexType.SC_HEVC;
+
+ /**
+ * Indexes can be tagged by Start Code in PES (Packetized Elementary Stream)
+ * according to ISO/IEC 13818-1.
+ * @hide
+ */
+ @IntDef(flag = true, value = {SC_INDEX_I_FRAME, SC_INDEX_P_FRAME, SC_INDEX_B_FRAME,
+ SC_INDEX_SEQUENCE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ScIndex {}
+
+ /**
+ * SC index for a new I-frame.
+ */
+ public static final int SC_INDEX_I_FRAME = Constants.DemuxScIndex.I_FRAME;
+ /**
+ * SC index for a new P-frame.
+ */
+ public static final int SC_INDEX_P_FRAME = Constants.DemuxScIndex.P_FRAME;
+ /**
+ * SC index for a new B-frame.
+ */
+ public static final int SC_INDEX_B_FRAME = Constants.DemuxScIndex.B_FRAME;
+ /**
+ * SC index for a new sequence.
+ */
+ public static final int SC_INDEX_SEQUENCE = Constants.DemuxScIndex.SEQUENCE;
+
+
+ /**
+ * Indexes can be tagged by NAL unit group in HEVC according to ISO/IEC 23008-2.
+ *
+ * @hide
+ */
+ @IntDef(flag = true,
+ value = {SC_HEVC_INDEX_SPS, SC_HEVC_INDEX_AUD, SC_HEVC_INDEX_SLICE_CE_BLA_W_LP,
+ SC_HEVC_INDEX_SLICE_BLA_W_RADL, SC_HEVC_INDEX_SLICE_BLA_N_LP,
+ SC_HEVC_INDEX_SLICE_IDR_W_RADL, SC_HEVC_INDEX_SLICE_IDR_N_LP,
+ SC_HEVC_INDEX_SLICE_TRAIL_CRA})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ScHevcIndex {}
+
+ /**
+ * SC HEVC index SPS.
+ */
+ public static final int SC_HEVC_INDEX_SPS = Constants.DemuxScHevcIndex.SPS;
+ /**
+ * SC HEVC index AUD.
+ */
+ public static final int SC_HEVC_INDEX_AUD = Constants.DemuxScHevcIndex.AUD;
+ /**
+ * SC HEVC index SLICE_CE_BLA_W_LP.
+ */
+ public static final int SC_HEVC_INDEX_SLICE_CE_BLA_W_LP =
+ Constants.DemuxScHevcIndex.SLICE_CE_BLA_W_LP;
+ /**
+ * SC HEVC index SLICE_BLA_W_RADL.
+ */
+ public static final int SC_HEVC_INDEX_SLICE_BLA_W_RADL =
+ Constants.DemuxScHevcIndex.SLICE_BLA_W_RADL;
+ /**
+ * SC HEVC index SLICE_BLA_N_LP.
+ */
+ public static final int SC_HEVC_INDEX_SLICE_BLA_N_LP =
+ Constants.DemuxScHevcIndex.SLICE_BLA_N_LP;
+ /**
+ * SC HEVC index SLICE_IDR_W_RADL.
+ */
+ public static final int SC_HEVC_INDEX_SLICE_IDR_W_RADL =
+ Constants.DemuxScHevcIndex.SLICE_IDR_W_RADL;
+ /**
+ * SC HEVC index SLICE_IDR_N_LP.
+ */
+ public static final int SC_HEVC_INDEX_SLICE_IDR_N_LP =
+ Constants.DemuxScHevcIndex.SLICE_IDR_N_LP;
+ /**
+ * SC HEVC index SLICE_TRAIL_CRA.
+ */
+ public static final int SC_HEVC_INDEX_SLICE_TRAIL_CRA =
+ Constants.DemuxScHevcIndex.SLICE_TRAIL_CRA;
+
/**
* @hide
*/
@IntDef(flag = true,
prefix = "SC_",
value = {
- TunerConstants.SC_INDEX_I_FRAME,
- TunerConstants.SC_INDEX_P_FRAME,
- TunerConstants.SC_INDEX_B_FRAME,
- TunerConstants.SC_INDEX_SEQUENCE,
- TunerConstants.SC_HEVC_INDEX_SPS,
- TunerConstants.SC_HEVC_INDEX_AUD,
- TunerConstants.SC_HEVC_INDEX_SLICE_CE_BLA_W_LP,
- TunerConstants.SC_HEVC_INDEX_SLICE_BLA_W_RADL,
- TunerConstants.SC_HEVC_INDEX_SLICE_BLA_N_LP,
- TunerConstants.SC_HEVC_INDEX_SLICE_IDR_W_RADL,
- TunerConstants.SC_HEVC_INDEX_SLICE_IDR_N_LP,
- TunerConstants.SC_HEVC_INDEX_SLICE_TRAIL_CRA,
+ SC_INDEX_I_FRAME,
+ SC_INDEX_P_FRAME,
+ SC_INDEX_B_FRAME,
+ SC_INDEX_SEQUENCE,
+ SC_HEVC_INDEX_SPS,
+ SC_HEVC_INDEX_AUD,
+ SC_HEVC_INDEX_SLICE_CE_BLA_W_LP,
+ SC_HEVC_INDEX_SLICE_BLA_W_RADL,
+ SC_HEVC_INDEX_SLICE_BLA_N_LP,
+ SC_HEVC_INDEX_SLICE_IDR_W_RADL,
+ SC_HEVC_INDEX_SLICE_IDR_N_LP,
+ SC_HEVC_INDEX_SLICE_TRAIL_CRA,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ScIndexMask {}
+
private final int mTsIndexMask;
private final int mScIndexType;
private final int mScIndexMask;
diff --git a/media/java/android/media/tv/tuner/frontend/AnalogFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/AnalogFrontendCapabilities.java
index aa64df5..096bc67 100644
--- a/media/java/android/media/tv/tuner/frontend/AnalogFrontendCapabilities.java
+++ b/media/java/android/media/tv/tuner/frontend/AnalogFrontendCapabilities.java
@@ -16,11 +16,14 @@
package android.media.tv.tuner.frontend;
+import android.annotation.SystemApi;
+
/**
* Capabilities for analog tuners.
*
* @hide
*/
+@SystemApi
public class AnalogFrontendCapabilities extends FrontendCapabilities {
@AnalogFrontendSettings.SignalType
private final int mTypeCap;
diff --git a/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java
index 61880ab..7b85fa8 100644
--- a/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java
@@ -195,7 +195,7 @@
/**
* Creates a builder for {@link AnalogFrontendSettings}.
*
- * @param the context of the caller.
+ * @param context the context of the caller.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
@NonNull
@@ -223,7 +223,7 @@
* Sets analog signal type.
*/
@NonNull
- public Builder setASignalType(@SignalType int signalType) {
+ public Builder setSignalType(@SignalType int signalType) {
mSignalType = signalType;
return this;
}
diff --git a/media/java/android/media/tv/tuner/frontend/Atsc3FrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendCapabilities.java
index 1fd1f63..7730912 100644
--- a/media/java/android/media/tv/tuner/frontend/Atsc3FrontendCapabilities.java
+++ b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendCapabilities.java
@@ -16,10 +16,14 @@
package android.media.tv.tuner.frontend;
+import android.annotation.SystemApi;
+
/**
* ATSC-3 Capabilities.
+ *
* @hide
*/
+@SystemApi
public class Atsc3FrontendCapabilities extends FrontendCapabilities {
private final int mBandwidthCap;
private final int mModulationCap;
@@ -63,7 +67,7 @@
* Gets code rate capability.
*/
@Atsc3FrontendSettings.CodeRate
- public int getCodeRateCapability() {
+ public int getPlpCodeRateCapability() {
return mCodeRateCap;
}
/**
diff --git a/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java
index 5e1ba72..85f3f72 100644
--- a/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.content.Context;
import android.hardware.tv.tuner.V1_0.Constants;
import android.media.tv.tuner.TunerUtils;
@@ -28,8 +29,10 @@
/**
* Frontend settings for ATSC-3.
+ *
* @hide
*/
+@SystemApi
public class Atsc3FrontendSettings extends FrontendSettings {
/** @hide */
@@ -273,9 +276,9 @@
public static final int DEMOD_OUTPUT_FORMAT_BASEBAND_PACKET =
Constants.FrontendAtsc3DemodOutputFormat.BASEBAND_PACKET;
- public final int mBandwidth;
- public final int mDemodOutputFormat;
- public final Atsc3PlpSettings[] mPlpSettings;
+ private final int mBandwidth;
+ private final int mDemodOutputFormat;
+ private final Atsc3PlpSettings[] mPlpSettings;
private Atsc3FrontendSettings(int frequency, int bandwidth, int demodOutputFormat,
Atsc3PlpSettings[] plpSettings) {
@@ -302,6 +305,7 @@
/**
* Gets PLP Settings.
*/
+ @NonNull
public Atsc3PlpSettings[] getPlpSettings() {
return mPlpSettings;
}
@@ -349,7 +353,7 @@
* Sets PLP Settings.
*/
@NonNull
- public Builder setPlpSettings(Atsc3PlpSettings[] plpSettings) {
+ public Builder setPlpSettings(@NonNull Atsc3PlpSettings[] plpSettings) {
mPlpSettings = plpSettings;
return this;
}
diff --git a/media/java/android/media/tv/tuner/frontend/Atsc3PlpSettings.java b/media/java/android/media/tv/tuner/frontend/Atsc3PlpSettings.java
index 43a68a0..fe61dbc 100644
--- a/media/java/android/media/tv/tuner/frontend/Atsc3PlpSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/Atsc3PlpSettings.java
@@ -18,13 +18,16 @@
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.content.Context;
import android.media.tv.tuner.TunerUtils;
/**
- * PLP settings for ATSC-3.
+ * Physical Layer Pipe (PLP) settings for ATSC-3.
+ *
* @hide
*/
+@SystemApi
public class Atsc3PlpSettings {
private final int mPlpId;
private final int mModulation;
diff --git a/media/java/android/media/tv/tuner/frontend/AtscFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/AtscFrontendCapabilities.java
index 0ff516d..eb21caa 100644
--- a/media/java/android/media/tv/tuner/frontend/AtscFrontendCapabilities.java
+++ b/media/java/android/media/tv/tuner/frontend/AtscFrontendCapabilities.java
@@ -16,10 +16,14 @@
package android.media.tv.tuner.frontend;
+import android.annotation.SystemApi;
+
/**
* ATSC Capabilities.
+ *
* @hide
*/
+@SystemApi
public class AtscFrontendCapabilities extends FrontendCapabilities {
private final int mModulationCap;
diff --git a/media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java
index 32901d8..fc82a1c 100644
--- a/media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.content.Context;
import android.hardware.tv.tuner.V1_0.Constants;
import android.media.tv.tuner.TunerUtils;
@@ -28,8 +29,10 @@
/**
* Frontend settings for ATSC.
+ *
* @hide
*/
+@SystemApi
public class AtscFrontendSettings extends FrontendSettings {
/** @hide */
diff --git a/media/java/android/media/tv/tuner/frontend/DvbcFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/DvbcFrontendCapabilities.java
index f3fbdb5..faa5434 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbcFrontendCapabilities.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbcFrontendCapabilities.java
@@ -16,12 +16,14 @@
package android.media.tv.tuner.frontend;
-import android.media.tv.tuner.TunerConstants.FrontendInnerFec;
+import android.annotation.SystemApi;
/**
* DVBC Capabilities.
+ *
* @hide
*/
+@SystemApi
public class DvbcFrontendCapabilities extends FrontendCapabilities {
private final int mModulationCap;
private final int mFecCap;
@@ -43,7 +45,7 @@
/**
* Gets inner FEC capability.
*/
- @FrontendInnerFec
+ @FrontendSettings.InnerFec
public int getFecCapability() {
return mFecCap;
}
diff --git a/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
index 3d212d3..bfa4f3f 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
@@ -19,9 +19,9 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.content.Context;
import android.hardware.tv.tuner.V1_0.Constants;
-import android.media.tv.tuner.TunerConstants.FrontendInnerFec;
import android.media.tv.tuner.TunerUtils;
import java.lang.annotation.Retention;
@@ -29,8 +29,10 @@
/**
* Frontend settings for DVBC.
+ *
* @hide
*/
+@SystemApi
public class DvbcFrontendSettings extends FrontendSettings {
/** @hide */
@@ -169,7 +171,7 @@
/**
* Gets Inner Forward Error Correction.
*/
- @FrontendInnerFec
+ @InnerFec
public long getFec() {
return mFec;
}
@@ -239,7 +241,7 @@
* Sets Inner Forward Error Correction.
*/
@NonNull
- public Builder setFec(@FrontendInnerFec long fec) {
+ public Builder setFec(@InnerFec long fec) {
mFec = fec;
return this;
}
diff --git a/media/java/android/media/tv/tuner/frontend/DvbsCodeRate.java b/media/java/android/media/tv/tuner/frontend/DvbsCodeRate.java
index 04d3375..2bdd379 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbsCodeRate.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbsCodeRate.java
@@ -18,22 +18,24 @@
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.content.Context;
-import android.media.tv.tuner.TunerConstants.FrontendInnerFec;
import android.media.tv.tuner.TunerUtils;
/**
* Code rate for DVBS.
+ *
* @hide
*/
+@SystemApi
public class DvbsCodeRate {
- private final long mFec;
+ private final long mInnerFec;
private final boolean mIsLinear;
private final boolean mIsShortFrames;
private final int mBitsPer1000Symbol;
private DvbsCodeRate(long fec, boolean isLinear, boolean isShortFrames, int bitsPer1000Symbol) {
- mFec = fec;
+ mInnerFec = fec;
mIsLinear = isLinear;
mIsShortFrames = isShortFrames;
mBitsPer1000Symbol = bitsPer1000Symbol;
@@ -42,9 +44,9 @@
/**
* Gets inner FEC.
*/
- @FrontendInnerFec
- public long getFec() {
- return mFec;
+ @FrontendSettings.InnerFec
+ public long getInnerFec() {
+ return mInnerFec;
}
/**
* Checks whether it's linear.
@@ -93,7 +95,7 @@
* Sets inner FEC.
*/
@NonNull
- public Builder setFec(@FrontendInnerFec long fec) {
+ public Builder setInnerFec(@FrontendSettings.InnerFec long fec) {
mFec = fec;
return this;
}
diff --git a/media/java/android/media/tv/tuner/frontend/DvbsFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/DvbsFrontendCapabilities.java
index bd615d0..1e25cf2 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbsFrontendCapabilities.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbsFrontendCapabilities.java
@@ -16,12 +16,14 @@
package android.media.tv.tuner.frontend;
-import android.media.tv.tuner.TunerConstants.FrontendInnerFec;
+import android.annotation.SystemApi;
/**
* DVBS Capabilities.
+ *
* @hide
*/
+@SystemApi
public class DvbsFrontendCapabilities extends FrontendCapabilities {
private final int mModulationCap;
private final long mInnerFecCap;
@@ -43,7 +45,7 @@
/**
* Gets inner FEC capability.
*/
- @FrontendInnerFec
+ @FrontendSettings.InnerFec
public long getInnerFecCapability() {
return mInnerFecCap;
}
diff --git a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
index 44dbcc0..4a4fed5 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.content.Context;
import android.hardware.tv.tuner.V1_0.Constants;
import android.media.tv.tuner.TunerUtils;
@@ -29,8 +30,10 @@
/**
* Frontend settings for DVBS.
+ *
* @hide
*/
+@SystemApi
public class DvbsFrontendSettings extends FrontendSettings {
/** @hide */
@IntDef(flag = true,
@@ -209,7 +212,7 @@
private final int mModulation;
- private final DvbsCodeRate mCoderate;
+ private final DvbsCodeRate mCodeRate;
private final int mSymbolRate;
private final int mRolloff;
private final int mPilot;
@@ -217,11 +220,11 @@
private final int mStandard;
private final int mVcmMode;
- private DvbsFrontendSettings(int frequency, int modulation, DvbsCodeRate coderate,
+ private DvbsFrontendSettings(int frequency, int modulation, DvbsCodeRate codeRate,
int symbolRate, int rolloff, int pilot, int inputStreamId, int standard, int vcm) {
super(frequency);
mModulation = modulation;
- mCoderate = coderate;
+ mCodeRate = codeRate;
mSymbolRate = symbolRate;
mRolloff = rolloff;
mPilot = pilot;
@@ -241,8 +244,8 @@
* Gets Code rate.
*/
@Nullable
- public DvbsCodeRate getCoderate() {
- return mCoderate;
+ public DvbsCodeRate getCodeRate() {
+ return mCodeRate;
}
/**
* Gets Symbol Rate in symbols per second.
@@ -302,7 +305,7 @@
*/
public static class Builder extends FrontendSettings.Builder<Builder> {
private int mModulation;
- private DvbsCodeRate mCoderate;
+ private DvbsCodeRate mCodeRate;
private int mSymbolRate;
private int mRolloff;
private int mPilot;
@@ -325,8 +328,8 @@
* Sets Code rate.
*/
@NonNull
- public Builder setCoderate(@Nullable DvbsCodeRate coderate) {
- mCoderate = coderate;
+ public Builder setCodeRate(@Nullable DvbsCodeRate codeRate) {
+ mCodeRate = codeRate;
return this;
}
/**
@@ -383,7 +386,7 @@
*/
@NonNull
public DvbsFrontendSettings build() {
- return new DvbsFrontendSettings(mFrequency, mModulation, mCoderate, mSymbolRate,
+ return new DvbsFrontendSettings(mFrequency, mModulation, mCodeRate, mSymbolRate,
mRolloff, mPilot, mInputStreamId, mStandard, mVcmMode);
}
diff --git a/media/java/android/media/tv/tuner/frontend/DvbtFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/DvbtFrontendCapabilities.java
index 0d47179..524952d 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbtFrontendCapabilities.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbtFrontendCapabilities.java
@@ -16,27 +16,31 @@
package android.media.tv.tuner.frontend;
+import android.annotation.SystemApi;
+
/**
* DVBT Capabilities.
+ *
* @hide
*/
+@SystemApi
public class DvbtFrontendCapabilities extends FrontendCapabilities {
private final int mTransmissionModeCap;
private final int mBandwidthCap;
private final int mConstellationCap;
- private final int mCoderateCap;
+ private final int mCodeRateCap;
private final int mHierarchyCap;
private final int mGuardIntervalCap;
private final boolean mIsT2Supported;
private final boolean mIsMisoSupported;
private DvbtFrontendCapabilities(int transmissionModeCap, int bandwidthCap,
- int constellationCap, int coderateCap, int hierarchyCap, int guardIntervalCap,
+ int constellationCap, int codeRateCap, int hierarchyCap, int guardIntervalCap,
boolean isT2Supported, boolean isMisoSupported) {
mTransmissionModeCap = transmissionModeCap;
mBandwidthCap = bandwidthCap;
mConstellationCap = constellationCap;
- mCoderateCap = coderateCap;
+ mCodeRateCap = codeRateCap;
mHierarchyCap = hierarchyCap;
mGuardIntervalCap = guardIntervalCap;
mIsT2Supported = isT2Supported;
@@ -67,9 +71,9 @@
/**
* Gets code rate capability.
*/
- @DvbtFrontendSettings.Coderate
+ @DvbtFrontendSettings.CodeRate
public int getCodeRateCapability() {
- return mCoderateCap;
+ return mCodeRateCap;
}
/**
* Gets hierarchy capability.
diff --git a/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
index 9a82de0..e99fd36f 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.content.Context;
import android.hardware.tv.tuner.V1_0.Constants;
import android.media.tv.tuner.TunerUtils;
@@ -28,8 +29,10 @@
/**
* Frontend settings for DVBT.
+ *
* @hide
*/
+@SystemApi
public class DvbtFrontendSettings extends FrontendSettings {
/** @hide */
@@ -220,7 +223,7 @@
value = {CODERATE_UNDEFINED, CODERATE_AUTO, CODERATE_1_2, CODERATE_2_3, CODERATE_3_4,
CODERATE_5_6, CODERATE_7_8, CODERATE_3_5, CODERATE_4_5, CODERATE_6_7, CODERATE_8_9})
@Retention(RetentionPolicy.SOURCE)
- public @interface Coderate {}
+ public @interface CodeRate {}
/**
* Code rate undefined.
@@ -347,8 +350,7 @@
public static final int STANDARD_T2 = Constants.FrontendDvbtStandard.T2;
/** @hide */
- @IntDef(flag = true,
- prefix = "PLP_MODE_",
+ @IntDef(prefix = "PLP_MODE_",
value = {PLP_MODE_UNDEFINED, PLP_MODE_AUTO, PLP_MODE_MANUAL})
@Retention(RetentionPolicy.SOURCE)
public @interface PlpMode {}
@@ -371,8 +373,8 @@
private final int mBandwidth;
private final int mConstellation;
private final int mHierarchy;
- private final int mHpCoderate;
- private final int mLpCoderate;
+ private final int mHpCodeRate;
+ private final int mLpCodeRate;
private final int mGuardInterval;
private final boolean mIsHighPriority;
private final int mStandard;
@@ -382,7 +384,7 @@
private final int mPlpGroupId;
private DvbtFrontendSettings(int frequency, int transmissionMode, int bandwidth,
- int constellation, int hierarchy, int hpCoderate, int lpCoderate, int guardInterval,
+ int constellation, int hierarchy, int hpCodeRate, int lpCodeRate, int guardInterval,
boolean isHighPriority, int standard, boolean isMiso, int plpMode, int plpId,
int plpGroupId) {
super(frequency);
@@ -390,8 +392,8 @@
mBandwidth = bandwidth;
mConstellation = constellation;
mHierarchy = hierarchy;
- mHpCoderate = hpCoderate;
- mLpCoderate = lpCoderate;
+ mHpCodeRate = hpCodeRate;
+ mLpCodeRate = lpCodeRate;
mGuardInterval = guardInterval;
mIsHighPriority = isHighPriority;
mStandard = standard;
@@ -432,16 +434,16 @@
/**
* Gets Code Rate for High Priority level.
*/
- @Coderate
- public int getHpCoderate() {
- return mHpCoderate;
+ @CodeRate
+ public int getHpCodeRate() {
+ return mHpCodeRate;
}
/**
* Gets Code Rate for Low Priority level.
*/
- @Coderate
- public int getLpCoderate() {
- return mLpCoderate;
+ @CodeRate
+ public int getLpCodeRate() {
+ return mLpCodeRate;
}
/**
* Gets Guard Interval.
@@ -509,8 +511,8 @@
private int mBandwidth;
private int mConstellation;
private int mHierarchy;
- private int mHpCoderate;
- private int mLpCoderate;
+ private int mHpCodeRate;
+ private int mLpCodeRate;
private int mGuardInterval;
private boolean mIsHighPriority;
private int mStandard;
@@ -558,16 +560,16 @@
* Sets Code Rate for High Priority level.
*/
@NonNull
- public Builder setHpCoderate(@Coderate int hpCoderate) {
- mHpCoderate = hpCoderate;
+ public Builder setHpCodeRate(@CodeRate int hpCodeRate) {
+ mHpCodeRate = hpCodeRate;
return this;
}
/**
* Sets Code Rate for Low Priority level.
*/
@NonNull
- public Builder setLpCoderate(@Coderate int lpCoderate) {
- mLpCoderate = lpCoderate;
+ public Builder setLpCodeRate(@CodeRate int lpCodeRate) {
+ mLpCodeRate = lpCodeRate;
return this;
}
/**
@@ -633,7 +635,7 @@
@NonNull
public DvbtFrontendSettings build() {
return new DvbtFrontendSettings(mFrequency, mTransmissionMode, mBandwidth,
- mConstellation, mHierarchy, mHpCoderate, mLpCoderate, mGuardInterval,
+ mConstellation, mHierarchy, mHpCodeRate, mLpCodeRate, mGuardInterval,
mIsHighPriority, mStandard, mIsMiso, mPlpMode, mPlpId, mPlpGroupId);
}
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/FrontendCapabilities.java
index e4f66b8..c03133d 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendCapabilities.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendCapabilities.java
@@ -16,10 +16,13 @@
package android.media.tv.tuner.frontend;
+import android.annotation.SystemApi;
+
/**
* Frontend capabilities.
*
* @hide
*/
+@SystemApi
public abstract class FrontendCapabilities {
}
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendInfo.java b/media/java/android/media/tv/tuner/frontend/FrontendInfo.java
index 360c84a..696d839 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendInfo.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendInfo.java
@@ -17,6 +17,7 @@
package android.media.tv.tuner.frontend;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.media.tv.tuner.frontend.FrontendSettings.Type;
import android.media.tv.tuner.frontend.FrontendStatus.FrontendStatusType;
import android.util.Range;
@@ -26,6 +27,7 @@
*
* @hide
*/
+@SystemApi
public class FrontendInfo {
private final int mId;
private final int mType;
@@ -102,12 +104,14 @@
* @return An array of supported status types.
*/
@FrontendStatusType
+ @NonNull
public int[] getStatusCapabilities() {
return mStatusCaps;
}
/**
* Gets frontend capabilities.
*/
+ @NonNull
public FrontendCapabilities getFrontendCapability() {
return mFrontendCap;
}
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
index b80b7cd..9071526 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
@@ -18,6 +18,7 @@
import android.annotation.IntDef;
import android.annotation.IntRange;
+import android.annotation.LongDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.hardware.tv.tuner.V1_0.Constants;
@@ -33,8 +34,9 @@
@SystemApi
public abstract class FrontendSettings {
/** @hide */
- @IntDef({TYPE_UNDEFINED, TYPE_ANALOG, TYPE_ATSC, TYPE_ATSC3, TYPE_DVBC, TYPE_DVBS, TYPE_DVBT,
- TYPE_ISDBS, TYPE_ISDBS3, TYPE_ISDBT})
+ @IntDef(prefix = "TYPE_",
+ value = {TYPE_UNDEFINED, TYPE_ANALOG, TYPE_ATSC, TYPE_ATSC3, TYPE_DVBC, TYPE_DVBS,
+ TYPE_DVBT, TYPE_ISDBS, TYPE_ISDBS3, TYPE_ISDBT})
@Retention(RetentionPolicy.SOURCE)
public @interface Type {}
@@ -79,10 +81,173 @@
*/
public static final int TYPE_ISDBT = Constants.FrontendType.ISDBT;
- private final int mFrequency;
+
/** @hide */
- public FrontendSettings(int frequency) {
+ @LongDef(flag = true,
+ prefix = "FEC_",
+ value = {FEC_UNDEFINED, FEC_AUTO, FEC_1_2, FEC_1_3, FEC_1_4, FEC_1_5, FEC_2_3, FEC_2_5,
+ FEC_2_9, FEC_3_4, FEC_3_5, FEC_4_5, FEC_4_15, FEC_5_6, FEC_5_9, FEC_6_7, FEC_7_8,
+ FEC_7_9, FEC_7_15, FEC_8_9, FEC_8_15, FEC_9_10, FEC_9_20, FEC_11_15, FEC_11_20,
+ FEC_11_45, FEC_13_18, FEC_13_45, FEC_14_45, FEC_23_36, FEC_25_36, FEC_26_45, FEC_28_45,
+ FEC_29_45, FEC_31_45, FEC_32_45, FEC_77_90})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface InnerFec {}
+
+ /**
+ * FEC not defined.
+ */
+ public static final long FEC_UNDEFINED = Constants.FrontendInnerFec.FEC_UNDEFINED;
+ /**
+ * hardware is able to detect and set FEC automatically.
+ */
+ public static final long FEC_AUTO = Constants.FrontendInnerFec.AUTO;
+ /**
+ * 1/2 conv. code rate.
+ */
+ public static final long FEC_1_2 = Constants.FrontendInnerFec.FEC_1_2;
+ /**
+ * 1/3 conv. code rate.
+ */
+ public static final long FEC_1_3 = Constants.FrontendInnerFec.FEC_1_3;
+ /**
+ * 1/4 conv. code rate.
+ */
+ public static final long FEC_1_4 = Constants.FrontendInnerFec.FEC_1_4;
+ /**
+ * 1/5 conv. code rate.
+ */
+ public static final long FEC_1_5 = Constants.FrontendInnerFec.FEC_1_5;
+ /**
+ * 2/3 conv. code rate.
+ */
+ public static final long FEC_2_3 = Constants.FrontendInnerFec.FEC_2_3;
+ /**
+ * 2/5 conv. code rate.
+ */
+ public static final long FEC_2_5 = Constants.FrontendInnerFec.FEC_2_5;
+ /**
+ * 2/9 conv. code rate.
+ */
+ public static final long FEC_2_9 = Constants.FrontendInnerFec.FEC_2_9;
+ /**
+ * 3/4 conv. code rate.
+ */
+ public static final long FEC_3_4 = Constants.FrontendInnerFec.FEC_3_4;
+ /**
+ * 3/5 conv. code rate.
+ */
+ public static final long FEC_3_5 = Constants.FrontendInnerFec.FEC_3_5;
+ /**
+ * 4/5 conv. code rate.
+ */
+ public static final long FEC_4_5 = Constants.FrontendInnerFec.FEC_4_5;
+ /**
+ * 4/15 conv. code rate.
+ */
+ public static final long FEC_4_15 = Constants.FrontendInnerFec.FEC_4_15;
+ /**
+ * 5/6 conv. code rate.
+ */
+ public static final long FEC_5_6 = Constants.FrontendInnerFec.FEC_5_6;
+ /**
+ * 5/9 conv. code rate.
+ */
+ public static final long FEC_5_9 = Constants.FrontendInnerFec.FEC_5_9;
+ /**
+ * 6/7 conv. code rate.
+ */
+ public static final long FEC_6_7 = Constants.FrontendInnerFec.FEC_6_7;
+ /**
+ * 7/8 conv. code rate.
+ */
+ public static final long FEC_7_8 = Constants.FrontendInnerFec.FEC_7_8;
+ /**
+ * 7/9 conv. code rate.
+ */
+ public static final long FEC_7_9 = Constants.FrontendInnerFec.FEC_7_9;
+ /**
+ * 7/15 conv. code rate.
+ */
+ public static final long FEC_7_15 = Constants.FrontendInnerFec.FEC_7_15;
+ /**
+ * 8/9 conv. code rate.
+ */
+ public static final long FEC_8_9 = Constants.FrontendInnerFec.FEC_8_9;
+ /**
+ * 8/15 conv. code rate.
+ */
+ public static final long FEC_8_15 = Constants.FrontendInnerFec.FEC_8_15;
+ /**
+ * 9/10 conv. code rate.
+ */
+ public static final long FEC_9_10 = Constants.FrontendInnerFec.FEC_9_10;
+ /**
+ * 9/20 conv. code rate.
+ */
+ public static final long FEC_9_20 = Constants.FrontendInnerFec.FEC_9_20;
+ /**
+ * 11/15 conv. code rate.
+ */
+ public static final long FEC_11_15 = Constants.FrontendInnerFec.FEC_11_15;
+ /**
+ * 11/20 conv. code rate.
+ */
+ public static final long FEC_11_20 = Constants.FrontendInnerFec.FEC_11_20;
+ /**
+ * 11/45 conv. code rate.
+ */
+ public static final long FEC_11_45 = Constants.FrontendInnerFec.FEC_11_45;
+ /**
+ * 13/18 conv. code rate.
+ */
+ public static final long FEC_13_18 = Constants.FrontendInnerFec.FEC_13_18;
+ /**
+ * 13/45 conv. code rate.
+ */
+ public static final long FEC_13_45 = Constants.FrontendInnerFec.FEC_13_45;
+ /**
+ * 14/45 conv. code rate.
+ */
+ public static final long FEC_14_45 = Constants.FrontendInnerFec.FEC_14_45;
+ /**
+ * 23/36 conv. code rate.
+ */
+ public static final long FEC_23_36 = Constants.FrontendInnerFec.FEC_23_36;
+ /**
+ * 25/36 conv. code rate.
+ */
+ public static final long FEC_25_36 = Constants.FrontendInnerFec.FEC_25_36;
+ /**
+ * 26/45 conv. code rate.
+ */
+ public static final long FEC_26_45 = Constants.FrontendInnerFec.FEC_26_45;
+ /**
+ * 28/45 conv. code rate.
+ */
+ public static final long FEC_28_45 = Constants.FrontendInnerFec.FEC_28_45;
+ /**
+ * 29/45 conv. code rate.
+ */
+ public static final long FEC_29_45 = Constants.FrontendInnerFec.FEC_29_45;
+ /**
+ * 31/45 conv. code rate.
+ */
+ public static final long FEC_31_45 = Constants.FrontendInnerFec.FEC_31_45;
+ /**
+ * 32/45 conv. code rate.
+ */
+ public static final long FEC_32_45 = Constants.FrontendInnerFec.FEC_32_45;
+ /**
+ * 77/90 conv. code rate.
+ */
+ public static final long FEC_77_90 = Constants.FrontendInnerFec.FEC_77_90;
+
+
+
+ private final int mFrequency;
+
+ FrontendSettings(int frequency) {
mFrequency = frequency;
}
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
index 088adff..c1b17d3 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
@@ -18,19 +18,19 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.hardware.tv.tuner.V1_0.Constants;
import android.media.tv.tuner.Lnb;
-import android.media.tv.tuner.TunerConstants.FrontendInnerFec;
-import android.media.tv.tuner.TunerConstants.FrontendModulation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
- * Frontend status
+ * Frontend status.
*
* @hide
*/
+@SystemApi
public class FrontendStatus {
/** @hide */
@@ -160,6 +160,52 @@
Constants.FrontendStatusType.ATSC3_PLP_INFO;
+ /** @hide */
+ @IntDef(value = {
+ DvbcFrontendSettings.MODULATION_UNDEFINED,
+ DvbcFrontendSettings.MODULATION_AUTO,
+ DvbcFrontendSettings.MODULATION_MOD_16QAM,
+ DvbcFrontendSettings.MODULATION_MOD_32QAM,
+ DvbcFrontendSettings.MODULATION_MOD_64QAM,
+ DvbcFrontendSettings.MODULATION_MOD_128QAM,
+ DvbcFrontendSettings.MODULATION_MOD_256QAM,
+ DvbsFrontendSettings.MODULATION_UNDEFINED,
+ DvbsFrontendSettings.MODULATION_AUTO,
+ DvbsFrontendSettings.MODULATION_MOD_QPSK,
+ DvbsFrontendSettings.MODULATION_MOD_8PSK,
+ DvbsFrontendSettings.MODULATION_MOD_16QAM,
+ DvbsFrontendSettings.MODULATION_MOD_16PSK,
+ DvbsFrontendSettings.MODULATION_MOD_32PSK,
+ DvbsFrontendSettings.MODULATION_MOD_ACM,
+ DvbsFrontendSettings.MODULATION_MOD_8APSK,
+ DvbsFrontendSettings.MODULATION_MOD_16APSK,
+ DvbsFrontendSettings.MODULATION_MOD_32APSK,
+ DvbsFrontendSettings.MODULATION_MOD_64APSK,
+ DvbsFrontendSettings.MODULATION_MOD_128APSK,
+ DvbsFrontendSettings.MODULATION_MOD_256APSK,
+ DvbsFrontendSettings.MODULATION_MOD_RESERVED,
+ IsdbsFrontendSettings.MODULATION_UNDEFINED,
+ IsdbsFrontendSettings.MODULATION_AUTO,
+ IsdbsFrontendSettings.MODULATION_MOD_BPSK,
+ IsdbsFrontendSettings.MODULATION_MOD_QPSK,
+ IsdbsFrontendSettings.MODULATION_MOD_TC8PSK,
+ Isdbs3FrontendSettings.MODULATION_UNDEFINED,
+ Isdbs3FrontendSettings.MODULATION_AUTO,
+ Isdbs3FrontendSettings.MODULATION_MOD_BPSK,
+ Isdbs3FrontendSettings.MODULATION_MOD_QPSK,
+ Isdbs3FrontendSettings.MODULATION_MOD_8PSK,
+ Isdbs3FrontendSettings.MODULATION_MOD_16APSK,
+ Isdbs3FrontendSettings.MODULATION_MOD_32APSK,
+ IsdbtFrontendSettings.MODULATION_UNDEFINED,
+ IsdbtFrontendSettings.MODULATION_AUTO,
+ IsdbtFrontendSettings.MODULATION_MOD_DQPSK,
+ IsdbtFrontendSettings.MODULATION_MOD_QPSK,
+ IsdbtFrontendSettings.MODULATION_MOD_16QAM,
+ IsdbtFrontendSettings.MODULATION_MOD_64QAM})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface FrontendModulation {}
+
+
private Boolean mIsDemodLocked;
private Integer mSnr;
private Integer mBer;
@@ -273,7 +319,7 @@
* Gets Inner Forward Error Correction type as specified in ETSI EN 300 468 V1.15.1
* and ETSI EN 302 307-2 V1.1.1.
*/
- @FrontendInnerFec
+ @FrontendSettings.InnerFec
public long getFec() {
if (mInnerFec == null) {
throw new IllegalStateException();
diff --git a/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendCapabilities.java
index 61cba1c..573f379 100644
--- a/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendCapabilities.java
+++ b/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendCapabilities.java
@@ -16,17 +16,21 @@
package android.media.tv.tuner.frontend;
+import android.annotation.SystemApi;
+
/**
* ISDBS-3 Capabilities.
+ *
* @hide
*/
+@SystemApi
public class Isdbs3FrontendCapabilities extends FrontendCapabilities {
private final int mModulationCap;
- private final int mCoderateCap;
+ private final int mCodeRateCap;
- private Isdbs3FrontendCapabilities(int modulationCap, int coderateCap) {
+ private Isdbs3FrontendCapabilities(int modulationCap, int codeRateCap) {
mModulationCap = modulationCap;
- mCoderateCap = coderateCap;
+ mCodeRateCap = codeRateCap;
}
/**
@@ -39,8 +43,8 @@
/**
* Gets code rate capability.
*/
- @Isdbs3FrontendSettings.Coderate
+ @Isdbs3FrontendSettings.CodeRate
public int getCodeRateCapability() {
- return mCoderateCap;
+ return mCodeRateCap;
}
}
diff --git a/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java
index a83d771..9b0e533 100644
--- a/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.content.Context;
import android.hardware.tv.tuner.V1_0.Constants;
import android.media.tv.tuner.TunerUtils;
@@ -28,8 +29,10 @@
/**
* Frontend settings for ISDBS-3.
+ *
* @hide
*/
+@SystemApi
public class Isdbs3FrontendSettings extends FrontendSettings {
/** @hide */
@IntDef(flag = true,
@@ -76,7 +79,7 @@
value = {CODERATE_UNDEFINED, CODERATE_AUTO, CODERATE_1_3, CODERATE_2_5, CODERATE_1_2,
CODERATE_3_5, CODERATE_2_3, CODERATE_3_4, CODERATE_7_9, CODERATE_4_5,
CODERATE_5_6, CODERATE_7_8, CODERATE_9_10})
- public @interface Coderate {}
+ public @interface CodeRate {}
/**
* Code rate undefined.
@@ -150,17 +153,17 @@
private final int mStreamId;
private final int mStreamIdType;
private final int mModulation;
- private final int mCoderate;
+ private final int mCodeRate;
private final int mSymbolRate;
private final int mRolloff;
private Isdbs3FrontendSettings(int frequency, int streamId, int streamIdType, int modulation,
- int coderate, int symbolRate, int rolloff) {
+ int codeRate, int symbolRate, int rolloff) {
super(frequency);
mStreamId = streamId;
mStreamIdType = streamIdType;
mModulation = modulation;
- mCoderate = coderate;
+ mCodeRate = codeRate;
mSymbolRate = symbolRate;
mRolloff = rolloff;
}
@@ -188,9 +191,9 @@
/**
* Gets Code rate.
*/
- @Coderate
- public int getCoderate() {
- return mCoderate;
+ @CodeRate
+ public int getCodeRate() {
+ return mCodeRate;
}
/**
* Gets Symbol Rate in symbols per second.
@@ -225,7 +228,7 @@
private int mStreamId;
private int mStreamIdType;
private int mModulation;
- private int mCoderate;
+ private int mCodeRate;
private int mSymbolRate;
private int mRolloff;
@@ -260,8 +263,8 @@
* Sets Code rate.
*/
@NonNull
- public Builder setCoderate(@Coderate int coderate) {
- mCoderate = coderate;
+ public Builder setCodeRate(@CodeRate int codeRate) {
+ mCodeRate = codeRate;
return this;
}
/**
@@ -287,7 +290,7 @@
@NonNull
public Isdbs3FrontendSettings build() {
return new Isdbs3FrontendSettings(mFrequency, mStreamId, mStreamIdType, mModulation,
- mCoderate, mSymbolRate, mRolloff);
+ mCodeRate, mSymbolRate, mRolloff);
}
@Override
diff --git a/media/java/android/media/tv/tuner/frontend/IsdbsFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/IsdbsFrontendCapabilities.java
index 8e5ecc4..38d2f1d 100644
--- a/media/java/android/media/tv/tuner/frontend/IsdbsFrontendCapabilities.java
+++ b/media/java/android/media/tv/tuner/frontend/IsdbsFrontendCapabilities.java
@@ -16,17 +16,21 @@
package android.media.tv.tuner.frontend;
+import android.annotation.SystemApi;
+
/**
* ISDBS Capabilities.
+ *
* @hide
*/
+@SystemApi
public class IsdbsFrontendCapabilities extends FrontendCapabilities {
private final int mModulationCap;
- private final int mCoderateCap;
+ private final int mCodeRateCap;
- private IsdbsFrontendCapabilities(int modulationCap, int coderateCap) {
+ private IsdbsFrontendCapabilities(int modulationCap, int codeRateCap) {
mModulationCap = modulationCap;
- mCoderateCap = coderateCap;
+ mCodeRateCap = codeRateCap;
}
/**
@@ -39,8 +43,8 @@
/**
* Gets code rate capability.
*/
- @IsdbsFrontendSettings.Coderate
+ @IsdbsFrontendSettings.CodeRate
public int getCodeRateCapability() {
- return mCoderateCap;
+ return mCodeRateCap;
}
}
diff --git a/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java
index bb809bf..14c08b1 100644
--- a/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.content.Context;
import android.hardware.tv.tuner.V1_0.Constants;
import android.media.tv.tuner.TunerUtils;
@@ -28,8 +29,10 @@
/**
* Frontend settings for ISDBS.
+ *
* @hide
*/
+@SystemApi
public class IsdbsFrontendSettings extends FrontendSettings {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -81,11 +84,10 @@
/** @hide */
@IntDef(flag = true,
prefix = "CODERATE_",
- value = {CODERATE_UNDEFINED, CODERATE_AUTO,
- CODERATE_1_2, CODERATE_2_3, CODERATE_3_4,
- CODERATE_5_6, CODERATE_7_8})
+ value = {CODERATE_UNDEFINED, CODERATE_AUTO, CODERATE_1_2, CODERATE_2_3, CODERATE_3_4,
+ CODERATE_5_6, CODERATE_7_8})
@Retention(RetentionPolicy.SOURCE)
- public @interface Coderate {}
+ public @interface CodeRate {}
/**
* Code rate undefined.
@@ -125,7 +127,7 @@
/**
* Rolloff type undefined.
*/
- public static final int ROLLOFF_UNDEFINED = Constants.FrontendIsdbs3Rolloff.UNDEFINED;
+ public static final int ROLLOFF_UNDEFINED = Constants.FrontendIsdbsRolloff.UNDEFINED;
/**
* 0,35 rolloff.
*/
@@ -135,17 +137,17 @@
private final int mStreamId;
private final int mStreamIdType;
private final int mModulation;
- private final int mCoderate;
+ private final int mCodeRate;
private final int mSymbolRate;
private final int mRolloff;
private IsdbsFrontendSettings(int frequency, int streamId, int streamIdType, int modulation,
- int coderate, int symbolRate, int rolloff) {
+ int codeRate, int symbolRate, int rolloff) {
super(frequency);
mStreamId = streamId;
mStreamIdType = streamIdType;
mModulation = modulation;
- mCoderate = coderate;
+ mCodeRate = codeRate;
mSymbolRate = symbolRate;
mRolloff = rolloff;
}
@@ -173,9 +175,9 @@
/**
* Gets Code rate.
*/
- @Coderate
- public int getCoderate() {
- return mCoderate;
+ @CodeRate
+ public int getCodeRate() {
+ return mCodeRate;
}
/**
* Gets Symbol Rate in symbols per second.
@@ -210,7 +212,7 @@
private int mStreamId;
private int mStreamIdType;
private int mModulation;
- private int mCoderate;
+ private int mCodeRate;
private int mSymbolRate;
private int mRolloff;
@@ -245,8 +247,8 @@
* Sets Code rate.
*/
@NonNull
- public Builder setCoderate(@Coderate int coderate) {
- mCoderate = coderate;
+ public Builder setCodeRate(@CodeRate int codeRate) {
+ mCodeRate = codeRate;
return this;
}
/**
@@ -272,7 +274,7 @@
@NonNull
public IsdbsFrontendSettings build() {
return new IsdbsFrontendSettings(mFrequency, mStreamId, mStreamIdType, mModulation,
- mCoderate, mSymbolRate, mRolloff);
+ mCodeRate, mSymbolRate, mRolloff);
}
@Override
diff --git a/media/java/android/media/tv/tuner/frontend/IsdbtFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/IsdbtFrontendCapabilities.java
index 19f04de..ffebc5a 100644
--- a/media/java/android/media/tv/tuner/frontend/IsdbtFrontendCapabilities.java
+++ b/media/java/android/media/tv/tuner/frontend/IsdbtFrontendCapabilities.java
@@ -16,23 +16,27 @@
package android.media.tv.tuner.frontend;
+import android.annotation.SystemApi;
+
/**
* ISDBT Capabilities.
+ *
* @hide
*/
+@SystemApi
public class IsdbtFrontendCapabilities extends FrontendCapabilities {
private final int mModeCap;
private final int mBandwidthCap;
private final int mModulationCap;
- private final int mCoderateCap;
+ private final int mCodeRateCap;
private final int mGuardIntervalCap;
private IsdbtFrontendCapabilities(int modeCap, int bandwidthCap, int modulationCap,
- int coderateCap, int guardIntervalCap) {
+ int codeRateCap, int guardIntervalCap) {
mModeCap = modeCap;
mBandwidthCap = bandwidthCap;
mModulationCap = modulationCap;
- mCoderateCap = coderateCap;
+ mCodeRateCap = codeRateCap;
mGuardIntervalCap = guardIntervalCap;
}
@@ -60,9 +64,9 @@
/**
* Gets code rate capability.
*/
- @DvbtFrontendSettings.Coderate
+ @DvbtFrontendSettings.CodeRate
public int getCodeRateCapability() {
- return mCoderateCap;
+ return mCodeRateCap;
}
/**
* Gets guard interval capability.
diff --git a/media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java
index 1510193..de3c80d 100644
--- a/media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java
@@ -19,17 +19,21 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.content.Context;
import android.hardware.tv.tuner.V1_0.Constants;
import android.media.tv.tuner.TunerUtils;
+import android.media.tv.tuner.frontend.DvbtFrontendSettings.CodeRate;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Frontend settings for ISDBT.
+ *
* @hide
*/
+@SystemApi
public class IsdbtFrontendSettings extends FrontendSettings {
/** @hide */
@IntDef(flag = true,
@@ -125,16 +129,18 @@
private final int mModulation;
private final int mBandwidth;
- private final int mCoderate;
+ private final int mMode;
+ private final int mCodeRate;
private final int mGuardInterval;
private final int mServiceAreaId;
- private IsdbtFrontendSettings(int frequency, int modulation, int bandwidth, int coderate,
- int guardInterval, int serviceAreaId) {
+ private IsdbtFrontendSettings(int frequency, int modulation, int bandwidth, int mode,
+ int codeRate, int guardInterval, int serviceAreaId) {
super(frequency);
mModulation = modulation;
mBandwidth = bandwidth;
- mCoderate = coderate;
+ mMode = mode;
+ mCodeRate = codeRate;
mGuardInterval = guardInterval;
mServiceAreaId = serviceAreaId;
}
@@ -154,11 +160,18 @@
return mBandwidth;
}
/**
+ * Gets ISDBT mode.
+ */
+ @Mode
+ public int getMode() {
+ return mMode;
+ }
+ /**
* Gets Code rate.
*/
- @DvbtFrontendSettings.Coderate
- public int getCoderate() {
- return mCoderate;
+ @CodeRate
+ public int getCodeRate() {
+ return mCodeRate;
}
/**
* Gets Guard Interval.
@@ -192,7 +205,8 @@
public static class Builder extends FrontendSettings.Builder<Builder> {
private int mModulation;
private int mBandwidth;
- private int mCoderate;
+ private int mMode;
+ private int mCodeRate;
private int mGuardInterval;
private int mServiceAreaId;
@@ -216,11 +230,19 @@
return this;
}
/**
+ * Sets ISDBT mode.
+ */
+ @NonNull
+ public Builder setMode(@Mode int mode) {
+ mMode = mode;
+ return this;
+ }
+ /**
* Sets Code rate.
*/
@NonNull
- public Builder setCoderate(@DvbtFrontendSettings.Coderate int coderate) {
- mCoderate = coderate;
+ public Builder setCodeRate(@CodeRate int codeRate) {
+ mCodeRate = codeRate;
return this;
}
/**
@@ -245,8 +267,8 @@
*/
@NonNull
public IsdbtFrontendSettings build() {
- return new IsdbtFrontendSettings(
- mFrequency, mModulation, mBandwidth, mCoderate, mGuardInterval, mServiceAreaId);
+ return new IsdbtFrontendSettings(mFrequency, mModulation, mBandwidth, mMode, mCodeRate,
+ mGuardInterval, mServiceAreaId);
}
@Override
diff --git a/packages/SystemUI/res/layout/bubble_flyout.xml b/packages/SystemUI/res/layout/bubble_flyout.xml
index 5f773f4..7ab0a0c 100644
--- a/packages/SystemUI/res/layout/bubble_flyout.xml
+++ b/packages/SystemUI/res/layout/bubble_flyout.xml
@@ -15,25 +15,50 @@
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <FrameLayout
+ <LinearLayout
android:id="@+id/bubble_flyout_text_container"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
+ android:orientation="horizontal"
android:clipToPadding="false"
- android:paddingLeft="@dimen/bubble_flyout_padding_x"
- android:paddingRight="@dimen/bubble_flyout_padding_x"
+ android:clipChildren="false"
+ android:paddingStart="@dimen/bubble_flyout_padding_x"
+ android:paddingEnd="@dimen/bubble_flyout_padding_x"
android:paddingTop="@dimen/bubble_flyout_padding_y"
android:paddingBottom="@dimen/bubble_flyout_padding_y"
android:translationZ="@dimen/bubble_flyout_elevation">
- <TextView
- android:id="@+id/bubble_flyout_text"
+ <ImageView
+ android:id="@+id/bubble_flyout_avatar"
+ android:layout_width="30dp"
+ android:layout_height="30dp"
+ android:layout_marginEnd="@dimen/bubble_flyout_avatar_message_space"
+ android:scaleType="centerInside"
+ android:src="@drawable/ic_create_bubble"/>
+
+ <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:fontFamily="@*android:string/config_bodyFontFamily"
- android:maxLines="2"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/>
+ android:orientation="vertical">
- </FrameLayout>
+ <TextView
+ android:id="@+id/bubble_flyout_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="@*android:string/config_bodyFontFamilyMedium"
+ android:maxLines="1"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/>
+
+ <TextView
+ android:id="@+id/bubble_flyout_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="@*android:string/config_bodyFontFamily"
+ android:maxLines="2"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/>
+
+ </LinearLayout>
+
+ </LinearLayout>
</merge>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 964a591..87de9d4 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -220,58 +220,6 @@
android:orientation="vertical">
<com.android.systemui.statusbar.notification.row.ButtonLinearLayout
- android:id="@+id/bubble"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="@dimen/notification_importance_button_padding"
- android:layout_marginBottom="@dimen/notification_importance_button_separation"
- android:clickable="true"
- android:focusable="true"
- android:background="@drawable/notification_guts_priority_button_bg"
- android:orientation="vertical">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:gravity="center"
- >
- <ImageView
- android:id="@+id/bubble_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_create_bubble"
- android:background="@android:color/transparent"
- android:tint="@color/notification_guts_priority_contents"
- android:clickable="false"
- android:focusable="false"/>
- <TextView
- android:id="@+id/bubble_label"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/notification_importance_drawable_padding"
- android:layout_weight="1"
- android:ellipsize="end"
- android:maxLines="1"
- android:clickable="false"
- android:focusable="false"
- android:textAppearance="@style/TextAppearance.NotificationImportanceButton"
- android:text="@string/notification_bubble_title"/>
- </LinearLayout>
- <TextView
- android:id="@+id/bubble_summary"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/notification_importance_button_description_top_margin"
- android:visibility="gone"
- android:text="@string/notification_channel_summary_bubble"
- android:clickable="false"
- android:focusable="false"
- android:ellipsize="end"
- android:maxLines="2"
- android:textAppearance="@style/TextAppearance.NotificationImportanceDetail"/>
- </com.android.systemui.statusbar.notification.row.ButtonLinearLayout>
-
- <com.android.systemui.statusbar.notification.row.ButtonLinearLayout
android:id="@+id/alert"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 26af4ec..65ca9f2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1097,13 +1097,15 @@
<!-- How much the bubble flyout text container is elevated. -->
<dimen name="bubble_flyout_elevation">4dp</dimen>
<!-- How much padding is around the left and right sides of the flyout text. -->
- <dimen name="bubble_flyout_padding_x">16dp</dimen>
+ <dimen name="bubble_flyout_padding_x">12dp</dimen>
<!-- How much padding is around the top and bottom of the flyout text. -->
- <dimen name="bubble_flyout_padding_y">8dp</dimen>
+ <dimen name="bubble_flyout_padding_y">10dp</dimen>
<!-- Size of the triangle that points from the flyout to the bubble stack. -->
<dimen name="bubble_flyout_pointer_size">6dp</dimen>
<!-- How much space to leave between the flyout (tip of the arrow) and the bubble stack. -->
<dimen name="bubble_flyout_space_from_bubble">8dp</dimen>
+ <!-- How much space to leave between the flyout text and the avatar displayed in the flyout. -->
+ <dimen name="bubble_flyout_avatar_message_space">6dp</dimen>
<!-- Padding between status bar and bubbles when displayed in expanded state -->
<dimen name="bubble_padding_top">16dp</dimen>
<!-- Size of individual bubbles. -->
diff --git a/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
new file mode 100644
index 0000000..2f8ef2d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
@@ -0,0 +1,216 @@
+/*
+ * 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.keyguard;
+
+import android.annotation.Nullable;
+import android.app.admin.IKeyguardCallback;
+import android.app.admin.IKeyguardClient;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.view.SurfaceControl;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.ViewGroup;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Encapsulates all logic for secondary lockscreen state management.
+ */
+public class AdminSecondaryLockScreenController {
+ private static final String TAG = "AdminSecondaryLockScreenController";
+ private static final int REMOTE_CONTENT_READY_TIMEOUT_MILLIS = 500;
+ private final KeyguardUpdateMonitor mUpdateMonitor;
+ private final Context mContext;
+ private final ViewGroup mParent;
+ private AdminSecurityView mView;
+ private Handler mHandler;
+ private IKeyguardClient mClient;
+ private KeyguardSecurityCallback mKeyguardCallback;
+ private SurfaceControl.Transaction mTransaction;
+
+ private final ServiceConnection mConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ mClient = IKeyguardClient.Stub.asInterface(service);
+ if (mView.isAttachedToWindow() && mClient != null) {
+ onSurfaceReady();
+
+ try {
+ service.linkToDeath(mKeyguardClientDeathRecipient, 0);
+ } catch (RemoteException e) {
+ // Failed to link to death, just dismiss and unbind the service for now.
+ Log.e(TAG, "Lost connection to secondary lockscreen service", e);
+ dismiss(KeyguardUpdateMonitor.getCurrentUser());
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName className) {
+ mClient = null;
+ }
+ };
+
+ private final IBinder.DeathRecipient mKeyguardClientDeathRecipient = () -> {
+ hide(); // hide also takes care of unlinking to death.
+ Log.d(TAG, "KeyguardClient service died");
+ };
+
+ private final IKeyguardCallback mCallback = new IKeyguardCallback.Stub() {
+ @Override
+ public void onDismiss() {
+ dismiss(UserHandle.getCallingUserId());
+ }
+
+ @Override
+ public void onSurfaceControlCreated(@Nullable SurfaceControl remoteSurfaceControl) {
+ if (mHandler != null) {
+ mHandler.removeCallbacksAndMessages(null);
+ }
+ if (remoteSurfaceControl != null) {
+ mTransaction.reparent(remoteSurfaceControl, mView.getSurfaceControl())
+ .apply();
+ } else {
+ dismiss(KeyguardUpdateMonitor.getCurrentUser());
+ }
+ }
+ };
+
+ private final KeyguardUpdateMonitorCallback mUpdateCallback =
+ new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onSecondaryLockscreenRequirementChanged(int userId) {
+ Intent newIntent = mUpdateMonitor.getSecondaryLockscreenRequirement(userId);
+ if (newIntent == null) {
+ dismiss(userId);
+ }
+ }
+ };
+
+ @VisibleForTesting
+ protected SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ final int userId = KeyguardUpdateMonitor.getCurrentUser();
+ mUpdateMonitor.registerCallback(mUpdateCallback);
+
+ if (mClient != null) {
+ onSurfaceReady();
+ }
+ mHandler.postDelayed(
+ () -> {
+ // If the remote content is not readied within the timeout period,
+ // move on without the secondary lockscreen.
+ dismiss(userId);
+ },
+ REMOTE_CONTENT_READY_TIMEOUT_MILLIS);
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ mUpdateMonitor.removeCallback(mUpdateCallback);
+ }
+ };
+
+ public AdminSecondaryLockScreenController(Context context, ViewGroup parent,
+ KeyguardUpdateMonitor updateMonitor, KeyguardSecurityCallback callback,
+ Handler handler, SurfaceControl.Transaction transaction) {
+ mContext = context;
+ mHandler = handler;
+ mParent = parent;
+ mTransaction = transaction;
+ mUpdateMonitor = updateMonitor;
+ mKeyguardCallback = callback;
+ mView = new AdminSecurityView(mContext, mSurfaceHolderCallback);
+ }
+
+ /**
+ * Displays the Admin security Surface view.
+ */
+ public void show(Intent serviceIntent) {
+ mContext.bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);
+ mParent.addView(mView);
+ }
+
+ /**
+ * Hides the Admin security Surface view.
+ */
+ public void hide() {
+ if (mView.isAttachedToWindow()) {
+ mParent.removeView(mView);
+ }
+ if (mClient != null) {
+ mClient.asBinder().unlinkToDeath(mKeyguardClientDeathRecipient, 0);
+ mContext.unbindService(mConnection);
+ mClient = null;
+ }
+ }
+
+ private void onSurfaceReady() {
+ try {
+ mClient.onSurfaceReady(mView.getInputToken(), mCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in onSurfaceReady", e);
+ dismiss(KeyguardUpdateMonitor.getCurrentUser());
+ }
+ }
+
+ private void dismiss(int userId) {
+ mHandler.removeCallbacksAndMessages(null);
+ if (mView != null && mView.isAttachedToWindow()
+ && userId == KeyguardUpdateMonitor.getCurrentUser()) {
+ hide();
+ mKeyguardCallback.dismiss(true, userId);
+ }
+ }
+
+ /**
+ * Custom {@link SurfaceView} used to allow a device admin to present an additional security
+ * screen.
+ */
+ private class AdminSecurityView extends SurfaceView {
+ private SurfaceHolder.Callback mSurfaceHolderCallback;
+
+ AdminSecurityView(Context context, SurfaceHolder.Callback surfaceHolderCallback) {
+ super(context);
+ mSurfaceHolderCallback = surfaceHolderCallback;
+ setZOrderOnTop(true);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ getHolder().addCallback(mSurfaceHolderCallback);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ getHolder().removeCallback(mSurfaceHolderCallback);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 9ae446e..ae78726 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -21,9 +21,12 @@
import android.app.AlertDialog;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
+import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.Rect;
import android.metrics.LogMaker;
+import android.os.Handler;
+import android.os.Looper;
import android.os.UserHandle;
import android.util.AttributeSet;
import android.util.Log;
@@ -31,6 +34,7 @@
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.MotionEvent;
+import android.view.SurfaceControl;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
@@ -90,6 +94,7 @@
private AlertDialog mAlertDialog;
private InjectionInflationController mInjectionInflationController;
private boolean mSwipeUpToRetry;
+ private AdminSecondaryLockScreenController mSecondaryLockScreenController;
private final ViewConfiguration mViewConfiguration;
private final SpringAnimation mSpringAnimation;
@@ -137,6 +142,9 @@
SystemUIFactory.getInstance().getRootComponent());
mViewConfiguration = ViewConfiguration.get(context);
mKeyguardStateController = Dependency.get(KeyguardStateController.class);
+ mSecondaryLockScreenController = new AdminSecondaryLockScreenController(context, this,
+ mUpdateMonitor, mCallback, new Handler(Looper.myLooper()),
+ new SurfaceControl.Transaction());
}
public void setSecurityCallback(SecurityCallback callback) {
@@ -157,6 +165,7 @@
mAlertDialog.dismiss();
mAlertDialog = null;
}
+ mSecondaryLockScreenController.hide();
if (mCurrentSecuritySelection != SecurityMode.None) {
getSecurityView(mCurrentSecuritySelection).onPause();
}
@@ -532,6 +541,15 @@
break;
}
}
+ // Check for device admin specified additional security measures.
+ if (finish) {
+ Intent secondaryLockscreenIntent =
+ mUpdateMonitor.getSecondaryLockscreenRequirement(targetUserId);
+ if (secondaryLockscreenIntent != null) {
+ mSecondaryLockScreenController.show(secondaryLockscreenIntent);
+ return false;
+ }
+ }
if (eventSubtype != -1) {
mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER)
.setType(MetricsEvent.TYPE_DISMISS).setSubtype(eventSubtype));
@@ -751,6 +769,5 @@
public void showUsabilityHint() {
mSecurityViewFlipper.showUsabilityHint();
}
-
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 65fc215..f03648a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -113,6 +113,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Map.Entry;
import java.util.TimeZone;
import java.util.function.Consumer;
@@ -334,6 +335,7 @@
private SparseBooleanArray mUserFingerprintAuthenticated = new SparseBooleanArray();
private SparseBooleanArray mUserFaceAuthenticated = new SparseBooleanArray();
private SparseBooleanArray mUserFaceUnlockRunning = new SparseBooleanArray();
+ private Map<Integer, Intent> mSecondaryLockscreenRequirement = new HashMap<Integer, Intent>();
private static int sCurrentUser;
private Runnable mUpdateBiometricListeningState = this::updateBiometricListeningState;
@@ -928,6 +930,45 @@
return mUserTrustIsManaged.get(userId) && !isTrustDisabled(userId);
}
+ private void updateSecondaryLockscreenRequirement(int userId) {
+ Intent oldIntent = mSecondaryLockscreenRequirement.get(userId);
+ boolean enabled = mDevicePolicyManager.isSecondaryLockscreenEnabled(userId);
+ boolean changed = false;
+
+ if (enabled && (oldIntent == null)) {
+ ResolveInfo resolveInfo =
+ mContext.getPackageManager().resolveService(
+ new Intent(
+ DevicePolicyManager.ACTION_BIND_SECONDARY_LOCKSCREEN_SERVICE),
+ 0);
+ if (resolveInfo != null) {
+ Intent newIntent = new Intent();
+ newIntent.setComponent(resolveInfo.serviceInfo.getComponentName());
+ mSecondaryLockscreenRequirement.put(userId, newIntent);
+ changed = true;
+ }
+ } else if (!enabled && (oldIntent != null)) {
+ mSecondaryLockscreenRequirement.put(userId, null);
+ changed = true;
+ }
+ if (changed) {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onSecondaryLockscreenRequirementChanged(userId);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns an Intent by which to bind to a service that will provide additional security screen
+ * content that must be shown prior to dismissing the keyguard for this user.
+ */
+ public Intent getSecondaryLockscreenRequirement(int userId) {
+ return mSecondaryLockscreenRequirement.get(userId);
+ }
+
/**
* Cached version of {@link TrustManager#isTrustUsuallyManaged(int)}.
*/
@@ -1113,7 +1154,8 @@
getSendingUserId()));
} else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
.equals(action)) {
- mHandler.sendEmptyMessage(MSG_DPM_STATE_CHANGED);
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_DPM_STATE_CHANGED,
+ getSendingUserId()));
} else if (ACTION_USER_UNLOCKED.equals(action)) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_UNLOCKED,
getSendingUserId(), 0));
@@ -1530,7 +1572,7 @@
handleDeviceProvisioned();
break;
case MSG_DPM_STATE_CHANGED:
- handleDevicePolicyManagerStateChanged();
+ handleDevicePolicyManagerStateChanged(msg.arg1);
break;
case MSG_USER_SWITCHING:
handleUserSwitching(msg.arg1, (IRemoteCallback) msg.obj);
@@ -1706,6 +1748,7 @@
mUserIsUnlocked.put(user, mUserManager.isUserUnlocked(user));
mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class);
mLogoutEnabled = mDevicePolicyManager.isLogoutEnabled();
+ updateSecondaryLockscreenRequirement(user);
List<UserInfo> allUsers = mUserManager.getUsers();
for (UserInfo userInfo : allUsers) {
mUserTrustIsUsuallyManaged.put(userInfo.id,
@@ -2046,9 +2089,10 @@
/**
* Handle {@link #MSG_DPM_STATE_CHANGED}
*/
- private void handleDevicePolicyManagerStateChanged() {
+ private void handleDevicePolicyManagerStateChanged(int userId) {
checkIsHandlerThread();
updateFingerprintListeningState();
+ updateSecondaryLockscreenRequirement(userId);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 04502f0..8e87b7a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -310,4 +310,9 @@
*/
public void onBiometricsCleared() { }
+ /**
+ * Called when the secondary lock screen requirement changes.
+ */
+ public void onSecondaryLockscreenRequirementChanged(int userId) { }
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index 7b4816f..044c5a0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -28,7 +28,6 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
-import android.os.UserManager;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
@@ -381,16 +380,7 @@
0 /* animateDurationMs */);
mSize = newSize;
} else if (newSize == AuthDialog.SIZE_LARGE) {
- final boolean isManagedProfile = Utils.isManagedProfile(mContext, mUserId);
-
- // If it's a managed profile, animate the contents and panel down, since the credential
- // contents will be shown on the same "layer" as the background. If it's not a managed
- // profile, animate the contents up and expand the panel to full-screen - the credential
- // contents will be shown on the same "layer" as the panel.
- final float translationY = isManagedProfile ?
- -getResources().getDimension(
- R.dimen.biometric_dialog_animation_translation_offset)
- : getResources().getDimension(
+ final float translationY = getResources().getDimension(
R.dimen.biometric_dialog_medium_to_large_translation_offset);
final AuthBiometricView biometricView = this;
@@ -421,26 +411,20 @@
biometricView.setAlpha(opacity);
});
- if (!isManagedProfile) {
- mPanelController.setUseFullScreen(true);
- mPanelController.updateForContentDimensions(
- mPanelController.getContainerWidth(),
- mPanelController.getContainerHeight(),
- mInjector.getMediumToLargeAnimationDurationMs());
- }
+ mPanelController.setUseFullScreen(true);
+ mPanelController.updateForContentDimensions(
+ mPanelController.getContainerWidth(),
+ mPanelController.getContainerHeight(),
+ mInjector.getMediumToLargeAnimationDurationMs());
// Start the animations together
AnimatorSet as = new AnimatorSet();
List<Animator> animators = new ArrayList<>();
animators.add(translationAnimator);
animators.add(opacityAnimator);
- if (isManagedProfile) {
- animators.add(mPanelController.getTranslationAnimator(translationY));
- animators.add(mPanelController.getAlphaAnimator(0));
- }
+
as.playTogether(animators);
- as.setDuration(isManagedProfile ? mInjector.getMediumToLargeAnimationDurationMs()
- : mInjector.getMediumToLargeAnimationDurationMs() * 2 / 3);
+ as.setDuration(mInjector.getMediumToLargeAnimationDurationMs() * 2 / 3);
as.start();
} else {
Log.e(TAG, "Unknown transition from: " + mSize + " to: " + newSize);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 4312a52..89446ad 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -19,11 +19,8 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.Drawable;
import android.hardware.biometrics.BiometricAuthenticator;
import android.os.Binder;
import android.os.Bundle;
@@ -168,9 +165,8 @@
R.layout.auth_container_view, root, false /* attachToRoot */);
}
- AuthPanelController getPanelController(Context context, View panelView,
- boolean isManagedProfile) {
- return new AuthPanelController(context, panelView, isManagedProfile);
+ AuthPanelController getPanelController(Context context, View panelView) {
+ return new AuthPanelController(context, panelView);
}
ImageView getBackgroundView(FrameLayout parent) {
@@ -256,10 +252,8 @@
final LayoutInflater factory = LayoutInflater.from(mContext);
mFrameLayout = mInjector.inflateContainerView(factory, this);
- final boolean isManagedProfile = Utils.isManagedProfile(mContext, mConfig.mUserId);
-
mPanelView = mInjector.getPanelView(mFrameLayout);
- mPanelController = mInjector.getPanelController(mContext, mPanelView, isManagedProfile);
+ mPanelController = mInjector.getPanelController(mContext, mPanelView);
// Inflate biometric view only if necessary.
if (Utils.isBiometricAllowed(mConfig.mBiometricPromptBundle)) {
@@ -281,16 +275,6 @@
mBiometricScrollView = mInjector.getBiometricScrollView(mFrameLayout);
mBackgroundView = mInjector.getBackgroundView(mFrameLayout);
- if (isManagedProfile) {
- final Drawable image = getResources().getDrawable(R.drawable.work_challenge_background,
- mContext.getTheme());
- final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
- image.setColorFilter(dpm.getOrganizationColorForUser(mConfig.mUserId),
- PorterDuff.Mode.DARKEN);
- mBackgroundView.setScaleType(ImageView.ScaleType.CENTER_CROP);
- mBackgroundView.setImageDrawable(image);
- }
-
addView(mFrameLayout);
setOnKeyListener((v, keyCode, event) -> {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthPanelController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthPanelController.java
index 4acbade..11503fb 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthPanelController.java
@@ -37,7 +37,6 @@
private final Context mContext;
private final View mPanelView;
- private final boolean mIsManagedProfile;
private boolean mUseFullScreen;
@@ -115,13 +114,6 @@
final float cornerRadius = mUseFullScreen ? 0 : mContext.getResources()
.getDimension(R.dimen.biometric_dialog_corner_size);
- // When going to full-screen for managed profiles, fade away so the managed profile
- // background behind this view becomes visible.
- final boolean shouldFadeAway = mUseFullScreen && mIsManagedProfile;
- final int alpha = shouldFadeAway ? 0 : 255;
- final float elevation = shouldFadeAway ? 0 :
- mContext.getResources().getDimension(R.dimen.biometric_dialog_elevation);
-
if (animateDurationMs > 0) {
// Animate margin
ValueAnimator marginAnimator = ValueAnimator.ofInt(mMargin, margin);
@@ -148,21 +140,11 @@
mContentWidth = (int) animation.getAnimatedValue();
});
- // Animate background
- ValueAnimator alphaAnimator = ValueAnimator.ofInt(
- mPanelView.getBackground().getAlpha(), alpha);
- alphaAnimator.addUpdateListener((animation) -> {
- if (shouldFadeAway) {
- mPanelView.getBackground().setAlpha((int) animation.getAnimatedValue());
- }
- });
-
// Play together
AnimatorSet as = new AnimatorSet();
as.setDuration(animateDurationMs);
as.setInterpolator(new AccelerateDecelerateInterpolator());
- as.playTogether(cornerAnimator, heightAnimator, widthAnimator, marginAnimator,
- alphaAnimator);
+ as.playTogether(cornerAnimator, heightAnimator, widthAnimator, marginAnimator);
as.start();
} else {
@@ -170,7 +152,6 @@
mCornerRadius = cornerRadius;
mContentWidth = contentWidth;
mContentHeight = contentHeight;
- mPanelView.getBackground().setAlpha(alpha);
mPanelView.invalidateOutline();
}
}
@@ -183,10 +164,9 @@
return mContainerHeight;
}
- AuthPanelController(Context context, View panelView, boolean isManagedProfile) {
+ AuthPanelController(Context context, View panelView) {
mContext = context;
mPanelView = panelView;
- mIsManagedProfile = isManagedProfile;
mCornerRadius = context.getResources()
.getDimension(R.dimen.biometric_dialog_corner_size);
mMargin = (int) context.getResources()
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 77c8e0b..2d9775d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -32,20 +32,17 @@
import android.content.pm.ShortcutInfo;
import android.content.res.Resources;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
-import android.os.Parcelable;
import android.os.UserHandle;
import android.provider.Settings;
-import android.text.TextUtils;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.R;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.List;
import java.util.Objects;
/**
@@ -85,6 +82,18 @@
/** Whether flyout text should be suppressed, regardless of any other flags or state. */
private boolean mSuppressFlyout;
+ /**
+ * Presentational info about the flyout.
+ */
+ public static class FlyoutMessage {
+ @Nullable public Drawable senderAvatar;
+ @Nullable public CharSequence senderName;
+ @Nullable public CharSequence message;
+ @Nullable public boolean isGroupChat;
+ }
+
+ private FlyoutMessage mFlyoutMessage;
+
public static String groupId(NotificationEntry entry) {
UserHandle user = entry.getSbn().getUser();
return user.getIdentifier() + "|" + entry.getSbn().getPackageName();
@@ -194,6 +203,7 @@
mShortcutInfo = info.shortcutInfo;
mAppName = info.appName;
+ mFlyoutMessage = info.flyoutMessage;
mExpandedView.update(this);
mIconView.update(this, info.badgedBubbleImage, info.dotColor, info.dotPath);
@@ -307,6 +317,10 @@
mSuppressFlyout = suppressFlyout;
}
+ FlyoutMessage getFlyoutMessage() {
+ return mFlyoutMessage;
+ }
+
/**
* Returns whether the notification for this bubble is a foreground service. It shows that this
* is an ongoing bubble.
@@ -346,14 +360,14 @@
* To populate the icon use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}.
*/
boolean usingShortcutInfo() {
- return BubbleExperimentConfig.isShortcutIntent(getBubbleIntent());
+ return mEntry.getBubbleMetadata().getShortcutId() != null;
}
@Nullable
PendingIntent getBubbleIntent() {
Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
if (data != null) {
- return data.getIntent();
+ return data.getBubbleIntent();
}
return null;
}
@@ -368,72 +382,6 @@
return intent;
}
- /**
- * Returns our best guess for the most relevant text summary of the latest update to this
- * notification, based on its type. Returns null if there should not be an update message.
- */
- CharSequence getUpdateMessage(Context context) {
- final Notification underlyingNotif = mEntry.getSbn().getNotification();
- final Class<? extends Notification.Style> style = underlyingNotif.getNotificationStyle();
-
- try {
- if (Notification.BigTextStyle.class.equals(style)) {
- // Return the big text, it is big so probably important. If it's not there use the
- // normal text.
- CharSequence bigText =
- underlyingNotif.extras.getCharSequence(Notification.EXTRA_BIG_TEXT);
- return !TextUtils.isEmpty(bigText)
- ? bigText
- : underlyingNotif.extras.getCharSequence(Notification.EXTRA_TEXT);
- } else if (Notification.MessagingStyle.class.equals(style)) {
- final List<Notification.MessagingStyle.Message> messages =
- Notification.MessagingStyle.Message.getMessagesFromBundleArray(
- (Parcelable[]) underlyingNotif.extras.get(
- Notification.EXTRA_MESSAGES));
-
- final Notification.MessagingStyle.Message latestMessage =
- Notification.MessagingStyle.findLatestIncomingMessage(messages);
-
- if (latestMessage != null) {
- final CharSequence personName = latestMessage.getSenderPerson() != null
- ? latestMessage.getSenderPerson().getName()
- : null;
-
- // Prepend the sender name if available since group chats also use messaging
- // style.
- if (!TextUtils.isEmpty(personName)) {
- return context.getResources().getString(
- R.string.notification_summary_message_format,
- personName,
- latestMessage.getText());
- } else {
- return latestMessage.getText();
- }
- }
- } else if (Notification.InboxStyle.class.equals(style)) {
- CharSequence[] lines =
- underlyingNotif.extras.getCharSequenceArray(Notification.EXTRA_TEXT_LINES);
-
- // Return the last line since it should be the most recent.
- if (lines != null && lines.length > 0) {
- return lines[lines.length - 1];
- }
- } else if (Notification.MediaStyle.class.equals(style)) {
- // Return nothing, media updates aren't typically useful as a text update.
- return null;
- } else {
- // Default to text extra.
- return underlyingNotif.extras.getCharSequence(Notification.EXTRA_TEXT);
- }
- } catch (ClassCastException | NullPointerException | ArrayIndexOutOfBoundsException e) {
- // No use crashing, we'll just return null and the caller will assume there's no update
- // message.
- e.printStackTrace();
- }
-
- return null;
- }
-
private int getDimenForPackageUser(Context context, int resId, String pkg, int userId) {
PackageManager pm = context.getPackageManager();
Resources r;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 644d8c4..e642d4e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -1075,8 +1075,12 @@
*/
static boolean canLaunchInActivityView(Context context, NotificationEntry entry) {
PendingIntent intent = entry.getBubbleMetadata() != null
- ? entry.getBubbleMetadata().getIntent()
+ ? entry.getBubbleMetadata().getBubbleIntent()
: null;
+ if (entry.getBubbleMetadata() != null
+ && entry.getBubbleMetadata().getShortcutId() != null) {
+ return true;
+ }
if (intent == null) {
Log.w(TAG, "Unable to create bubble -- no intent: " + entry.getKey());
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index ccbbb24..cc0824e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -218,7 +218,7 @@
}
mPendingBubbles.remove(bubble); // No longer pending once we're here
Bubble prevBubble = getBubbleWithKey(bubble.getKey());
- suppressFlyout |= !shouldShowFlyout(bubble.getEntry());
+ suppressFlyout |= !bubble.getEntry().getRanking().visuallyInterruptive();
if (prevBubble == null) {
// Create a new bubble
@@ -329,14 +329,6 @@
return bubbleChildren;
}
- private boolean shouldShowFlyout(NotificationEntry notif) {
- if (notif.getRanking().visuallyInterruptive()) {
- return true;
- }
- return hasBubbleWithKey(notif.getKey())
- && !getBubbleWithKey(notif.getKey()).showInShade();
- }
-
private void doAdd(Bubble bubble) {
if (DEBUG_BUBBLE_DATA) {
Log.d(TAG, "doAdd: " + bubble);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 53a7cfd..48ce4e9 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -357,7 +357,7 @@
if (isNew) {
mBubbleIntent = mBubble.getBubbleIntent();
- if (mBubbleIntent != null) {
+ if (mBubbleIntent != null || mBubble.getShortcutInfo() != null) {
setContentVisibility(false);
mActivityView.setVisibility(VISIBLE);
}
@@ -543,7 +543,8 @@
}
private boolean usingActivityView() {
- return mBubbleIntent != null && mActivityView != null;
+ return (mBubbleIntent != null || mBubble.getShortcutInfo() != null)
+ && mActivityView != null;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
index 4c1cf49..4252f72 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
@@ -29,7 +29,6 @@
import android.app.PendingIntent;
import android.app.Person;
import android.content.Context;
-import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
import android.graphics.Color;
@@ -182,7 +181,7 @@
ShortcutInfo info = getShortcutInfo(context, entry.getSbn().getPackageName(),
entry.getSbn().getUser(), shortcutId);
if (info != null) {
- metadata = createForShortcut(context, entry);
+ metadata = createForShortcut(shortcutId);
}
// Replace existing metadata with shortcut, or we're bubbling for experiment
@@ -259,30 +258,17 @@
}
if (intent != null) {
return new Notification.BubbleMetadata.Builder()
+ .createIntentBubble(intent, icon)
.setDesiredHeight(BUBBLE_HEIGHT)
- .setIcon(icon)
- .setIntent(intent)
.build();
}
return null;
}
- static Notification.BubbleMetadata createForShortcut(Context context, NotificationEntry entry) {
- // ShortcutInfo does not return an icon, instead a Drawable, lets just use
- // notification icon for BubbleMetadata.
- Icon icon = entry.getSbn().getNotification().getSmallIcon();
-
- // ShortcutInfo does not return the intent, lets make a fake but identifiable
- // intent so we can still add bubbleMetadata
- if (sDummyShortcutIntent == null) {
- Intent i = new Intent(SHORTCUT_DUMMY_INTENT);
- sDummyShortcutIntent = PendingIntent.getActivity(context, 0, i,
- PendingIntent.FLAG_UPDATE_CURRENT);
- }
+ static Notification.BubbleMetadata createForShortcut(String shortcutId) {
return new Notification.BubbleMetadata.Builder()
.setDesiredHeight(BUBBLE_HEIGHT)
- .setIcon(icon)
- .setIntent(sDummyShortcutIntent)
+ .createShortcutBubble(shortcutId)
.build();
}
@@ -304,10 +290,6 @@
: null;
}
- static boolean isShortcutIntent(PendingIntent intent) {
- return intent != null && intent.equals(sDummyShortcutIntent);
- }
-
static List<Person> getPeopleFromNotification(NotificationEntry entry) {
Bundle extras = entry.getSbn().getNotification().extras;
ArrayList<Person> personList = new ArrayList<>();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
index 78e98eb..4194352 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
@@ -32,11 +32,13 @@
import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.drawable.ShapeDrawable;
+import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.widget.FrameLayout;
+import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.Nullable;
@@ -65,7 +67,9 @@
private final float mCornerRadius;
private final ViewGroup mFlyoutTextContainer;
- private final TextView mFlyoutText;
+ private final ImageView mSenderAvatar;
+ private final TextView mSenderText;
+ private final TextView mMessageText;
/** Values related to the 'new' dot which we use to figure out where to collapse the flyout. */
private final float mNewDotRadius;
@@ -142,7 +146,9 @@
LayoutInflater.from(context).inflate(R.layout.bubble_flyout, this, true);
mFlyoutTextContainer = findViewById(R.id.bubble_flyout_text_container);
- mFlyoutText = mFlyoutTextContainer.findViewById(R.id.bubble_flyout_text);
+ mSenderText = findViewById(R.id.bubble_flyout_name);
+ mSenderAvatar = findViewById(R.id.bubble_flyout_avatar);
+ mMessageText = mFlyoutTextContainer.findViewById(R.id.bubble_flyout_text);
final Resources res = getResources();
mFlyoutPadding = res.getDimensionPixelSize(R.dimen.bubble_flyout_padding_x);
@@ -204,9 +210,34 @@
/** Configures the flyout, collapsed into to dot form. */
void setupFlyoutStartingAsDot(
- CharSequence updateMessage, PointF stackPos, float parentWidth,
- boolean arrowPointingLeft, int dotColor, @Nullable Runnable onLayoutComplete,
- @Nullable Runnable onHide, float[] dotCenter, boolean hideDot) {
+ Bubble.FlyoutMessage flyoutMessage,
+ PointF stackPos,
+ float parentWidth,
+ boolean arrowPointingLeft,
+ int dotColor,
+ @Nullable Runnable onLayoutComplete,
+ @Nullable Runnable onHide,
+ float[] dotCenter,
+ boolean hideDot) {
+
+ if (flyoutMessage.senderAvatar != null && flyoutMessage.isGroupChat) {
+ mSenderAvatar.setVisibility(VISIBLE);
+ mSenderAvatar.setImageDrawable(flyoutMessage.senderAvatar);
+ } else {
+ mSenderAvatar.setVisibility(GONE);
+ mSenderAvatar.setTranslationX(0);
+ mMessageText.setTranslationX(0);
+ mSenderText.setTranslationX(0);
+ }
+
+ // Name visibility
+ if (!TextUtils.isEmpty(flyoutMessage.senderName)) {
+ mSenderText.setText(flyoutMessage.senderName);
+ mSenderText.setVisibility(VISIBLE);
+ } else {
+ mSenderText.setVisibility(GONE);
+ }
+
mArrowPointingLeft = arrowPointingLeft;
mDotColor = dotColor;
mOnHide = onHide;
@@ -217,15 +248,15 @@
// Set the flyout TextView's max width in terms of percent, and then subtract out the
// padding so that the entire flyout view will be the desired width (rather than the
// TextView being the desired width + extra padding).
- mFlyoutText.setMaxWidth(
+ mMessageText.setMaxWidth(
(int) (parentWidth * FLYOUT_MAX_WIDTH_PERCENT) - mFlyoutPadding * 2);
- mFlyoutText.setText(updateMessage);
+ mMessageText.setText(flyoutMessage.message);
// Wait for the TextView to lay out so we know its line count.
post(() -> {
float restingTranslationY;
// Multi line flyouts get top-aligned to the bubble.
- if (mFlyoutText.getLineCount() > 1) {
+ if (mMessageText.getLineCount() > 1) {
restingTranslationY = stackPos.y + mBubbleIconTopPadding;
} else {
// Single line flyouts are vertically centered with respect to the bubble.
@@ -289,11 +320,20 @@
mPercentStillFlyout = (1f - mPercentTransitionedToDot);
// Move and fade out the text.
- mFlyoutText.setTranslationX(
- (mArrowPointingLeft ? -getWidth() : getWidth()) * mPercentTransitionedToDot);
- mFlyoutText.setAlpha(clampPercentage(
+ final float translationX = mPercentTransitionedToDot
+ * (mArrowPointingLeft ? -getWidth() : getWidth());
+ final float alpha = clampPercentage(
(mPercentStillFlyout - (1f - BubbleStackView.FLYOUT_DRAG_PERCENT_DISMISS))
- / BubbleStackView.FLYOUT_DRAG_PERCENT_DISMISS));
+ / BubbleStackView.FLYOUT_DRAG_PERCENT_DISMISS);
+
+ mMessageText.setTranslationX(translationX);
+ mMessageText.setAlpha(alpha);
+
+ mSenderText.setTranslationX(translationX);
+ mSenderText.setAlpha(alpha);
+
+ mSenderAvatar.setTranslationX(translationX);
+ mSenderAvatar.setAlpha(alpha);
// Reduce the elevation towards that of the topmost bubble.
setTranslationZ(
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
index b32dbb7..3b818db 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
@@ -18,6 +18,7 @@
import android.app.Notification;
import android.content.Context;
import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutInfo;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
@@ -48,16 +49,19 @@
/**
* Returns the drawable that the developer has provided to display in the bubble.
*/
- Drawable getBubbleDrawable(Bubble b, Context context) {
- if (b.getShortcutInfo() != null && b.usingShortcutInfo()) {
+ Drawable getBubbleDrawable(Context context, ShortcutInfo shortcutInfo,
+ Notification.BubbleMetadata metadata) {
+ if (shortcutInfo != null) {
LauncherApps launcherApps =
(LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
int density = context.getResources().getConfiguration().densityDpi;
- return launcherApps.getShortcutIconDrawable(b.getShortcutInfo(), density);
+ return launcherApps.getShortcutIconDrawable(shortcutInfo, density);
} else {
- Notification.BubbleMetadata metadata = b.getEntry().getBubbleMetadata();
- Icon ic = metadata.getIcon();
- return ic.loadDrawable(context);
+ Icon ic = metadata.getBubbleIcon();
+ if (ic != null) {
+ return ic.loadDrawable(context);
+ }
+ return null;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 02314bf..54a42a6 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -1377,9 +1377,10 @@
*/
@VisibleForTesting
void animateInFlyoutForBubble(Bubble bubble) {
- final CharSequence updateMessage = bubble.getUpdateMessage(getContext());
+ Bubble.FlyoutMessage flyoutMessage = bubble.getFlyoutMessage();
final BadgedImageView bubbleView = bubble.getIconView();
- if (updateMessage == null
+ if (flyoutMessage == null
+ || flyoutMessage.message == null
|| !bubble.showFlyout()
|| isExpanded()
|| mIsExpansionAnimating
@@ -1432,8 +1433,8 @@
};
mFlyout.postDelayed(mAnimateInFlyout, 200);
};
- mFlyout.setupFlyoutStartingAsDot(
- updateMessage, mStackAnimationController.getStackPosition(), getWidth(),
+ mFlyout.setupFlyoutStartingAsDot(flyoutMessage,
+ mStackAnimationController.getStackPosition(), getWidth(),
mStackAnimationController.isStackOnLeftSide(),
bubble.getIconView().getDotColor() /* dotColor */,
expandFlyoutAfterDelay /* onLayoutComplete */,
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
index 41f5028..e705584 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
@@ -21,6 +21,9 @@
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import android.annotation.NonNull;
+import android.app.Notification;
+import android.app.Person;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -31,7 +34,9 @@
import android.graphics.Path;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
+import android.os.Parcelable;
import android.service.notification.StatusBarNotification;
+import android.text.TextUtils;
import android.util.Log;
import android.util.PathParser;
import android.view.LayoutInflater;
@@ -41,8 +46,10 @@
import com.android.internal.graphics.ColorUtils;
import com.android.launcher3.icons.BitmapInfo;
import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import java.lang.ref.WeakReference;
+import java.util.List;
/**
* Simple task to inflate views & load necessary info to display a bubble.
@@ -98,6 +105,9 @@
}
}
+ /**
+ * Info necessary to render a bubble.
+ */
static class BubbleViewInfo {
BadgedImageView imageView;
BubbleExpandedView expandedView;
@@ -106,6 +116,7 @@
Bitmap badgedBubbleImage;
int dotColor;
Path dotPath;
+ Bubble.FlyoutMessage flyoutMessage;
@Nullable
static BubbleViewInfo populate(Context c, BubbleStackView stackView,
@@ -126,15 +137,22 @@
StatusBarNotification sbn = b.getEntry().getSbn();
String packageName = sbn.getPackageName();
- // Shortcut info for this bubble
- String shortcutId = sbn.getNotification().getShortcutId();
- if (BubbleExperimentConfig.useShortcutInfoToBubble(c)
- && shortcutId != null) {
- info.shortcutInfo = BubbleExperimentConfig.getShortcutInfo(c,
- packageName,
- sbn.getUser(), shortcutId);
+ // Real shortcut info for this bubble
+ String bubbleShortcutId = b.getEntry().getBubbleMetadata().getShortcutId();
+ if (bubbleShortcutId != null) {
+ info.shortcutInfo = BubbleExperimentConfig.getShortcutInfo(c, packageName,
+ sbn.getUser(), bubbleShortcutId);
+ } else {
+ // Check for experimental shortcut
+ String shortcutId = sbn.getNotification().getShortcutId();
+ if (BubbleExperimentConfig.useShortcutInfoToBubble(c) && shortcutId != null) {
+ info.shortcutInfo = BubbleExperimentConfig.getShortcutInfo(c,
+ packageName,
+ sbn.getUser(), shortcutId);
+ }
}
+
// App name & app icon
PackageManager pm = c.getPackageManager();
ApplicationInfo appInfo;
@@ -158,7 +176,8 @@
}
// Badged bubble image
- Drawable bubbleDrawable = iconFactory.getBubbleDrawable(b, c);
+ Drawable bubbleDrawable = iconFactory.getBubbleDrawable(c, info.shortcutInfo,
+ b.getEntry().getBubbleMetadata());
BitmapInfo badgeBitmapInfo = iconFactory.getBadgeBitmap(badgedIcon);
info.badgedBubbleImage = iconFactory.getBubbleBitmap(bubbleDrawable,
badgeBitmapInfo).icon;
@@ -176,7 +195,80 @@
info.dotPath = iconPath;
info.dotColor = ColorUtils.blendARGB(badgeBitmapInfo.color,
Color.WHITE, WHITE_SCRIM_ALPHA);
+
+ // Flyout
+ info.flyoutMessage = extractFlyoutMessage(c, b.getEntry());
return info;
}
}
+
+
+ /**
+ * Returns our best guess for the most relevant text summary of the latest update to this
+ * notification, based on its type. Returns null if there should not be an update message.
+ */
+ @NonNull
+ static Bubble.FlyoutMessage extractFlyoutMessage(Context context,
+ NotificationEntry entry) {
+ final Notification underlyingNotif = entry.getSbn().getNotification();
+ final Class<? extends Notification.Style> style = underlyingNotif.getNotificationStyle();
+
+ Bubble.FlyoutMessage bubbleMessage = new Bubble.FlyoutMessage();
+ bubbleMessage.isGroupChat = underlyingNotif.extras.getBoolean(
+ Notification.EXTRA_IS_GROUP_CONVERSATION);
+ try {
+ if (Notification.BigTextStyle.class.equals(style)) {
+ // Return the big text, it is big so probably important. If it's not there use the
+ // normal text.
+ CharSequence bigText =
+ underlyingNotif.extras.getCharSequence(Notification.EXTRA_BIG_TEXT);
+ bubbleMessage.message = !TextUtils.isEmpty(bigText)
+ ? bigText
+ : underlyingNotif.extras.getCharSequence(Notification.EXTRA_TEXT);
+ return bubbleMessage;
+ } else if (Notification.MessagingStyle.class.equals(style)) {
+ final List<Notification.MessagingStyle.Message> messages =
+ Notification.MessagingStyle.Message.getMessagesFromBundleArray(
+ (Parcelable[]) underlyingNotif.extras.get(
+ Notification.EXTRA_MESSAGES));
+
+ final Notification.MessagingStyle.Message latestMessage =
+ Notification.MessagingStyle.findLatestIncomingMessage(messages);
+ if (latestMessage != null) {
+ bubbleMessage.message = latestMessage.getText();
+ Person sender = latestMessage.getSenderPerson();
+ bubbleMessage.senderName = sender != null
+ ? sender.getName()
+ : null;
+ bubbleMessage.senderAvatar = sender != null
+ ? sender.getIcon().loadDrawable(context)
+ : null;
+ return bubbleMessage;
+ }
+ } else if (Notification.InboxStyle.class.equals(style)) {
+ CharSequence[] lines =
+ underlyingNotif.extras.getCharSequenceArray(Notification.EXTRA_TEXT_LINES);
+
+ // Return the last line since it should be the most recent.
+ if (lines != null && lines.length > 0) {
+ bubbleMessage.message = lines[lines.length - 1];
+ return bubbleMessage;
+ }
+ } else if (Notification.MediaStyle.class.equals(style)) {
+ // Return nothing, media updates aren't typically useful as a text update.
+ return bubbleMessage;
+ } else {
+ // Default to text extra.
+ bubbleMessage.message =
+ underlyingNotif.extras.getCharSequence(Notification.EXTRA_TEXT);
+ return bubbleMessage;
+ }
+ } catch (ClassCastException | NullPointerException | ArrayIndexOutOfBoundsException e) {
+ // No use crashing, we'll just return null and the caller will assume there's no update
+ // message.
+ e.printStackTrace();
+ }
+
+ return bubbleMessage;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
index 66ed864..bbf2dde 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
@@ -188,7 +188,9 @@
return false;
}
- if (entry.getBubbleMetadata() == null || entry.getBubbleMetadata().getIntent() == null) {
+ if (entry.getBubbleMetadata() == null
+ || (entry.getBubbleMetadata().getShortcutId() == null
+ && entry.getBubbleMetadata().getBubbleIntent() == null)) {
if (DEBUG) {
Log.d(TAG, "No bubble up: notification: " + sbn.getKey()
+ " doesn't have valid metadata");
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
new file mode 100644
index 0000000..1954b39
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
@@ -0,0 +1,207 @@
+/*
+ * 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.keyguard;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.AdditionalAnswers.answerVoid;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.admin.IKeyguardCallback;
+import android.app.admin.IKeyguardClient;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+import android.testing.ViewUtils;
+import android.view.SurfaceControl;
+import android.view.SurfaceView;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+
+@RunWithLooper
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
+
+ private static final int TARGET_USER_ID = KeyguardUpdateMonitor.getCurrentUser();
+
+ private AdminSecondaryLockScreenController mTestController;
+ private ComponentName mComponentName;
+ private Intent mServiceIntent;
+ private TestableLooper mTestableLooper;
+ private ViewGroup mParent;
+
+ @Mock
+ private Handler mHandler;
+ @Mock
+ private IKeyguardClient.Stub mKeyguardClient;
+ @Mock
+ private KeyguardSecurityCallback mKeyguardCallback;
+ @Mock
+ private KeyguardUpdateMonitor mUpdateMonitor;
+ @Spy
+ private StubTransaction mTransaction;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mParent = spy(new FrameLayout(mContext));
+ ViewUtils.attachView(mParent);
+
+ mTestableLooper = TestableLooper.get(this);
+ mComponentName = new ComponentName(mContext, "FakeKeyguardClient.class");
+ mServiceIntent = new Intent().setComponent(mComponentName);
+
+ mContext.addMockService(mComponentName, mKeyguardClient);
+ // Have Stub.asInterface return the mocked interface.
+ when(mKeyguardClient.queryLocalInterface(anyString())).thenReturn(mKeyguardClient);
+ when(mKeyguardClient.asBinder()).thenReturn(mKeyguardClient);
+
+ mTestController = new AdminSecondaryLockScreenController(
+ mContext, mParent, mUpdateMonitor, mKeyguardCallback, mHandler, mTransaction);
+ }
+
+ @Test
+ public void testShow() throws Exception {
+ doAnswer(invocation -> {
+ IKeyguardCallback callback = (IKeyguardCallback) invocation.getArguments()[1];
+ callback.onSurfaceControlCreated(new SurfaceControl());
+ return null;
+ }).when(mKeyguardClient).onSurfaceReady(any(), any(IKeyguardCallback.class));
+
+ mTestController.show(mServiceIntent);
+
+ verifySurfaceReady();
+ verify(mTransaction).reparent(any(), any());
+ assertThat(mContext.isBound(mComponentName)).isTrue();
+ }
+
+ @Test
+ public void testShow_dismissedByCallback() throws Exception {
+ doAnswer(invocation -> {
+ IKeyguardCallback callback = (IKeyguardCallback) invocation.getArguments()[1];
+ callback.onDismiss();
+ return null;
+ }).when(mKeyguardClient).onSurfaceReady(any(), any(IKeyguardCallback.class));
+
+ mTestController.show(mServiceIntent);
+
+ verifyViewDismissed(verifySurfaceReady());
+ }
+
+ @Test
+ public void testHide() throws Exception {
+ // Show the view first, then hide.
+ doAnswer(invocation -> {
+ IKeyguardCallback callback = (IKeyguardCallback) invocation.getArguments()[1];
+ callback.onSurfaceControlCreated(new SurfaceControl());
+ return null;
+ }).when(mKeyguardClient).onSurfaceReady(any(), any(IKeyguardCallback.class));
+
+ mTestController.show(mServiceIntent);
+ SurfaceView v = verifySurfaceReady();
+
+ mTestController.hide();
+ verify(mParent).removeView(v);
+ assertThat(mContext.isBound(mComponentName)).isFalse();
+ }
+
+ @Test
+ public void testHide_notShown() throws Exception {
+ mTestController.hide();
+ // Nothing should happen if trying to hide when the view isn't attached yet.
+ verify(mParent, never()).removeView(any(SurfaceView.class));
+ }
+
+ @Test
+ public void testDismissed_onSurfaceReady_RemoteException() throws Exception {
+ doThrow(new RemoteException()).when(mKeyguardClient)
+ .onSurfaceReady(any(), any(IKeyguardCallback.class));
+
+ mTestController.show(mServiceIntent);
+
+ verifyViewDismissed(verifySurfaceReady());
+ }
+
+ @Test
+ public void testDismissed_onSurfaceReady_timeout() throws Exception {
+ // Mocked KeyguardClient never handles the onSurfaceReady, so the operation times out,
+ // resulting in the view being dismissed.
+ doAnswer(answerVoid(Runnable::run)).when(mHandler)
+ .postDelayed(any(Runnable.class), anyLong());
+
+ mTestController.show(mServiceIntent);
+
+ verifyViewDismissed(verifySurfaceReady());
+ }
+
+ private SurfaceView verifySurfaceReady() throws Exception {
+ mTestableLooper.processAllMessages();
+ ArgumentCaptor<SurfaceView> captor = ArgumentCaptor.forClass(SurfaceView.class);
+ verify(mParent).addView(captor.capture());
+
+ mTestableLooper.processAllMessages();
+ verify(mKeyguardClient).onSurfaceReady(any(), any(IKeyguardCallback.class));
+ return captor.getValue();
+ }
+
+ private void verifyViewDismissed(SurfaceView v) throws Exception {
+ verify(mParent).removeView(v);
+ verify(mKeyguardCallback).dismiss(true, TARGET_USER_ID);
+ assertThat(mContext.isBound(mComponentName)).isFalse();
+ }
+
+ /**
+ * Stubbed {@link SurfaceControl.Transaction} class that can be used when unit testing to
+ * avoid calls to native code.
+ */
+ private class StubTransaction extends SurfaceControl.Transaction {
+ @Override
+ public void apply() {
+ }
+
+ @Override
+ public SurfaceControl.Transaction reparent(SurfaceControl sc, SurfaceControl newParent) {
+ return this;
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 12da006..b3c2ba3 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -34,12 +34,16 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.Activity;
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
@@ -519,6 +523,52 @@
assertThat(mKeyguardUpdateMonitor.isTrustUsuallyManaged(user)).isFalse();
}
+ @Test
+ public void testSecondaryLockscreenRequirement() {
+ int user = KeyguardUpdateMonitor.getCurrentUser();
+ String packageName = "fake.test.package";
+ String cls = "FakeService";
+ ServiceInfo serviceInfo = new ServiceInfo();
+ serviceInfo.packageName = packageName;
+ serviceInfo.name = cls;
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.serviceInfo = serviceInfo;
+ when(mPackageManager.resolveService(any(Intent.class), eq(0))).thenReturn(resolveInfo);
+ when(mDevicePolicyManager.isSecondaryLockscreenEnabled(eq(user))).thenReturn(true, false);
+
+ // Initially null.
+ assertThat(mKeyguardUpdateMonitor.getSecondaryLockscreenRequirement(user)).isNull();
+
+ // Set non-null after DPM change.
+ setBroadcastReceiverPendingResult(mKeyguardUpdateMonitor.mBroadcastAllReceiver);
+ Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
+ mKeyguardUpdateMonitor.mBroadcastAllReceiver.onReceive(getContext(), intent);
+ mTestableLooper.processAllMessages();
+
+ Intent storedIntent = mKeyguardUpdateMonitor.getSecondaryLockscreenRequirement(user);
+ assertThat(storedIntent.getComponent().getClassName()).isEqualTo(cls);
+ assertThat(storedIntent.getComponent().getPackageName()).isEqualTo(packageName);
+
+ // Back to null after another DPM change.
+ mKeyguardUpdateMonitor.mBroadcastAllReceiver.onReceive(getContext(), intent);
+ mTestableLooper.processAllMessages();
+ assertThat(mKeyguardUpdateMonitor.getSecondaryLockscreenRequirement(user)).isNull();
+ }
+
+ private void setBroadcastReceiverPendingResult(BroadcastReceiver receiver) {
+ BroadcastReceiver.PendingResult pendingResult =
+ new BroadcastReceiver.PendingResult(Activity.RESULT_OK,
+ "resultData",
+ /* resultExtras= */ null,
+ BroadcastReceiver.PendingResult.TYPE_UNREGISTERED,
+ /* ordered= */ true,
+ /* sticky= */ false,
+ /* token= */ null,
+ UserHandle.myUserId(),
+ /* flags= */ 0);
+ receiver.setPendingResult(pendingResult);
+ }
+
private Intent putPhoneInfo(Intent intent, Bundle data, Boolean simInited) {
int subscription = simInited
? 1/* mock subid=1 */ : SubscriptionManager.DUMMY_SUBSCRIPTION_ID_BASE;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
index 25bcb54..f264259 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
@@ -211,8 +211,7 @@
}
@Override
- public AuthPanelController getPanelController(Context context, View view,
- boolean isManagedProfile) {
+ public AuthPanelController getPanelController(Context context, View view) {
return mock(AuthPanelController.class);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
index c4ae409..b09603d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
@@ -228,7 +228,7 @@
}
@Test
- public void sameUpdate_NotInShade_showFlyout() {
+ public void sameUpdate_NotInShade_NotVisuallyInterruptive_dontShowFlyout() {
// Setup
mBubbleData.setListener(mListener);
@@ -247,7 +247,7 @@
// Verify
BubbleData.Update update = mUpdateCaptor.getValue();
- assertThat(update.updatedBubble.showFlyout()).isTrue();
+ assertThat(update.updatedBubble.showFlyout()).isFalse();
}
// COLLAPSED / ADD
@@ -952,9 +952,8 @@
long postTime) {
// BubbleMetadata
Notification.BubbleMetadata bubbleMetadata = new Notification.BubbleMetadata.Builder()
- .setIntent(mExpandIntent)
+ .createIntentBubble(mExpandIntent, Icon.createWithResource("", 0))
.setDeleteIntent(mDeleteIntent)
- .setIcon(Icon.createWithResource("", 0))
.build();
// Notification -> BubbleMetadata
Notification notification = mNotificationTestHelper.createNotification(false,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleFlyoutViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleFlyoutViewTest.java
index 376ecf7..fd6e2ee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleFlyoutViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleFlyoutViewTest.java
@@ -45,14 +45,22 @@
public class BubbleFlyoutViewTest extends SysuiTestCase {
private BubbleFlyoutView mFlyout;
private TextView mFlyoutText;
+ private TextView mSenderName;
private float[] mDotCenter = new float[2];
+ private Bubble.FlyoutMessage mFlyoutMessage;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+
+ mFlyoutMessage = new Bubble.FlyoutMessage();
+ mFlyoutMessage.senderName = "Josh";
+ mFlyoutMessage.message = "Hello";
+
mFlyout = new BubbleFlyoutView(getContext());
mFlyoutText = mFlyout.findViewById(R.id.bubble_flyout_text);
+ mSenderName = mFlyout.findViewById(R.id.bubble_flyout_name);
mDotCenter[0] = 30;
mDotCenter[1] = 30;
}
@@ -60,19 +68,21 @@
@Test
public void testShowFlyout_isVisible() {
mFlyout.setupFlyoutStartingAsDot(
- "Hello", new PointF(100, 100), 500, true, Color.WHITE, null, null, mDotCenter,
+ mFlyoutMessage,
+ new PointF(100, 100), 500, true, Color.WHITE, null, null, mDotCenter,
false);
mFlyout.setVisibility(View.VISIBLE);
assertEquals("Hello", mFlyoutText.getText());
+ assertEquals("Josh", mSenderName.getText());
assertEquals(View.VISIBLE, mFlyout.getVisibility());
}
@Test
public void testFlyoutHide_runsCallback() {
Runnable after = Mockito.mock(Runnable.class);
- mFlyout.setupFlyoutStartingAsDot(
- "Hello", new PointF(100, 100), 500, true, Color.WHITE, null, after, mDotCenter,
+ mFlyout.setupFlyoutStartingAsDot(mFlyoutMessage,
+ new PointF(100, 100), 500, true, Color.WHITE, null, after, mDotCenter,
false);
mFlyout.hideFlyout();
@@ -81,8 +91,8 @@
@Test
public void testSetCollapsePercent() {
- mFlyout.setupFlyoutStartingAsDot(
- "Hello", new PointF(100, 100), 500, true, Color.WHITE, null, null, mDotCenter,
+ mFlyout.setupFlyoutStartingAsDot(mFlyoutMessage,
+ new PointF(100, 100), 500, true, Color.WHITE, null, null, mDotCenter,
false);
mFlyout.setVisibility(View.VISIBLE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java
index 3c42fd1..02f721c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java
@@ -45,7 +45,6 @@
private Notification mNotif;
private NotificationEntry mEntry;
- private Bubble mBubble;
private Bundle mExtras;
@Before
@@ -58,7 +57,6 @@
mEntry = new NotificationEntryBuilder()
.setNotification(mNotif)
.build();
- mBubble = new Bubble(mEntry);
}
@Test
@@ -66,7 +64,8 @@
final String msg = "Hello there!";
doReturn(Notification.Style.class).when(mNotif).getNotificationStyle();
mExtras.putCharSequence(Notification.EXTRA_TEXT, msg);
- assertEquals(msg, mBubble.getUpdateMessage(mContext));
+ assertEquals(msg, BubbleViewInfoTask.extractFlyoutMessage(mContext,
+ mEntry).message);
}
@Test
@@ -77,7 +76,8 @@
mExtras.putCharSequence(Notification.EXTRA_BIG_TEXT, msg);
// Should be big text, not the small text.
- assertEquals(msg, mBubble.getUpdateMessage(mContext));
+ assertEquals(msg, BubbleViewInfoTask.extractFlyoutMessage(mContext,
+ mEntry).message);
}
@Test
@@ -85,7 +85,8 @@
doReturn(Notification.MediaStyle.class).when(mNotif).getNotificationStyle();
// Media notifs don't get update messages.
- assertNull(mBubble.getUpdateMessage(mContext));
+ assertNull(BubbleViewInfoTask.extractFlyoutMessage(mContext,
+ mEntry).message);
}
@Test
@@ -100,7 +101,8 @@
"Really? I prefer them that way."});
// Should be the last one only.
- assertEquals("Really? I prefer them that way.", mBubble.getUpdateMessage(mContext));
+ assertEquals("Really? I prefer them that way.",
+ BubbleViewInfoTask.extractFlyoutMessage(mContext, mEntry).message);
}
@Test
@@ -115,6 +117,10 @@
"Oh, hello!", 0, "Mady").toBundle()});
// Should be the last one only.
- assertEquals("Mady: Oh, hello!", mBubble.getUpdateMessage(mContext));
+ assertEquals("Oh, hello!",
+ BubbleViewInfoTask.extractFlyoutMessage(mContext, mEntry).message);
+ assertEquals("Mady",
+ BubbleViewInfoTask.extractFlyoutMessage(mContext,
+ mEntry).senderName);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java
index 677a6fc..1693e7f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java
@@ -557,8 +557,8 @@
private NotificationEntry createBubble() {
Notification.BubbleMetadata data = new Notification.BubbleMetadata.Builder()
- .setIntent(PendingIntent.getActivity(mContext, 0, new Intent(), 0))
- .setIcon(Icon.createWithResource(mContext.getResources(), R.drawable.android))
+ .createIntentBubble(PendingIntent.getActivity(mContext, 0, new Intent(), 0),
+ Icon.createWithResource(mContext.getResources(), R.drawable.android))
.build();
Notification n = new Notification.Builder(getContext(), "a")
.setContentTitle("title")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index 61e43b0..457bbe2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -383,9 +383,9 @@
PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, target, 0);
return new BubbleMetadata.Builder()
- .setIntent(bubbleIntent)
+ .createIntentBubble(bubbleIntent,
+ Icon.createWithResource(mContext, R.drawable.android))
.setDeleteIntent(deleteIntent)
- .setIcon(Icon.createWithResource(mContext, R.drawable.android))
.setDesiredHeight(314)
.build();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index 857e964..5fc40cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -195,8 +195,8 @@
new Intent(mContext, BubblesTestActivity.class), 0);
mBubbleSbn = new SbnBuilder(mSbn).setBubbleMetadata(
new Notification.BubbleMetadata.Builder()
- .setIntent(bubbleIntent)
- .setIcon(Icon.createWithResource(mContext, R.drawable.android)).build())
+ .createIntentBubble(bubbleIntent,
+ Icon.createWithResource(mContext, R.drawable.android)).build())
.build();
mBubbleEntry = new NotificationEntryBuilder().setSbn(mBubbleSbn).build();
diff --git a/services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java b/services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java
index 9bf0bd3..afb20ec 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java
@@ -78,7 +78,18 @@
final String option = getNextOption();
if (option != null) {
if (option.equals("--user")) {
- return UserHandle.parseUserArg(getNextArgRequired());
+ int userId = UserHandle.parseUserArg(getNextArgRequired());
+ if (userId == UserHandle.USER_CURRENT) {
+ return ActivityManager.getCurrentUser();
+ } else if (userId == UserHandle.USER_ALL) {
+ getErrPrintWriter().println("USER_ALL not supported. Specify a user.");
+ return null;
+ } else if (userId < 0) {
+ getErrPrintWriter().println("Invalid user: " + userId);
+ return null;
+ } else {
+ return userId;
+ }
} else {
getErrPrintWriter().println("Unknown option: " + option);
return null;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d9fbc85..00c0b3e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4866,7 +4866,7 @@
updateProcessForegroundLocked(app, false, 0, false);
app.hasShownUi = false;
app.setDebugging(false);
- app.cached = false;
+ app.setCached(false);
app.killedByAm = false;
app.killed = false;
@@ -12154,7 +12154,7 @@
r.lastSwapPss*1024, new StringBuilder()));
proto.write(ProcessOomProto.Detail.LAST_CACHED_PSS, DebugUtils.sizeValueToString(
r.lastCachedPss*1024, new StringBuilder()));
- proto.write(ProcessOomProto.Detail.CACHED, r.cached);
+ proto.write(ProcessOomProto.Detail.CACHED, r.isCached());
proto.write(ProcessOomProto.Detail.EMPTY, r.empty);
proto.write(ProcessOomProto.Detail.HAS_ABOVE_CLIENT, r.hasAboveClient);
@@ -12281,7 +12281,7 @@
pw.println();
pw.print(prefix);
pw.print(" ");
- pw.print("cached="); pw.print(r.cached);
+ pw.print("cached="); pw.print(r.isCached());
pw.print(" empty="); pw.print(r.empty);
pw.print(" hasAboveClient="); pw.println(r.hasAboveClient);
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index e7d6eb7..3f0e2ce 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -1759,7 +1759,7 @@
return 0;
}
- private void switchUserAndWaitForComplete(int userId) throws RemoteException {
+ private boolean switchUserAndWaitForComplete(int userId) throws RemoteException {
// Register switch observer.
final CountDownLatch switchLatch = new CountDownLatch(1);
mInterface.registerUserSwitchObserver(
@@ -1773,7 +1773,7 @@
}, ActivityManagerShellCommand.class.getName());
// Switch.
- mInterface.switchUser(userId);
+ boolean switched = mInterface.switchUser(userId);
// Wait.
try {
@@ -1781,6 +1781,7 @@
} catch (InterruptedException e) {
getErrPrintWriter().println("Thread interrupted unexpectedly.");
}
+ return switched;
}
int runSwitchUser(PrintWriter pw) throws RemoteException {
@@ -1802,12 +1803,18 @@
}
int userId = Integer.parseInt(getNextArgRequired());
+ boolean switched;
if (wait) {
- switchUserAndWaitForComplete(userId);
+ switched = switchUserAndWaitForComplete(userId);
} else {
- mInterface.switchUser(userId);
+ switched = mInterface.switchUser(userId);
}
- return 0;
+ if (switched) {
+ return 0;
+ } else {
+ pw.printf("Failed to switch to user %d\n", userId);
+ return 1;
+ }
}
int runGetCurrentUser(PrintWriter pw) throws RemoteException {
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index be14b3b..63331fa 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -71,6 +71,9 @@
import android.app.ActivityManager;
import android.app.ApplicationExitInfo;
import android.app.usage.UsageEvents;
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.content.Context;
import android.content.pm.ServiceInfo;
import android.os.Build;
@@ -106,7 +109,6 @@
*/
public final class OomAdjuster {
private static final String TAG = "OomAdjuster";
-
static final String OOM_ADJ_REASON_METHOD = "updateOomAdj";
static final String OOM_ADJ_REASON_NONE = OOM_ADJ_REASON_METHOD + "_meh";
static final String OOM_ADJ_REASON_ACTIVITY = OOM_ADJ_REASON_METHOD + "_activityChange";
@@ -123,6 +125,17 @@
static final String OOM_ADJ_REASON_PROCESS_END = OOM_ADJ_REASON_METHOD + "_processEnd";
/**
+ * Flag {@link Context#BIND_INCLUDE_CAPABILITIES} is used
+ * to pass while-in-use capabilities from client process to bound service. In targetSdkVersion
+ * R and above, if client is a TOP activity, when this flag is present, bound service gets all
+ * while-in-use capabilities; when this flag is not present, bound service gets no while-in-use
+ * capabilitiy from client.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion=android.os.Build.VERSION_CODES.Q)
+ static final long PROCESS_CAPABILITY_CHANGE_ID = 136274596L;
+
+ /**
* For some direct access we need to power manager.
*/
PowerManagerInternal mLocalPowerManager;
@@ -248,7 +261,7 @@
return updateOomAdjLocked(app, oomAdjReason);
}
final ProcessRecord TOP_APP = mService.getTopAppLocked();
- final boolean wasCached = app.cached;
+ final boolean wasCached = app.isCached();
mAdjSeq++;
@@ -261,7 +274,7 @@
boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false,
SystemClock.uptimeMillis());
if (oomAdjAll
- && (wasCached != app.cached || app.getCurRawAdj() == ProcessList.UNKNOWN_ADJ)) {
+ && (wasCached != app.isCached() || app.getCurRawAdj() == ProcessList.UNKNOWN_ADJ)) {
// Changed to/from cached state, so apps after it in the LRU
// list may also be changed.
updateOomAdjLocked(oomAdjReason);
@@ -337,7 +350,7 @@
mAdjSeq++;
// Firstly, try to see if the importance of itself gets changed
- final boolean wasCached = app.cached;
+ final boolean wasCached = app.isCached();
final int oldAdj = app.getCurRawAdj();
final int cachedAdj = oldAdj >= ProcessList.CACHED_APP_MIN_ADJ
? oldAdj : ProcessList.UNKNOWN_ADJ;
@@ -347,7 +360,7 @@
app.resetCachedInfo();
boolean success = updateOomAdjLocked(app, cachedAdj, topApp, false,
SystemClock.uptimeMillis());
- if (!success || (wasCached == app.cached && oldAdj != ProcessList.INVALID_ADJ
+ if (!success || (wasCached == app.isCached() && oldAdj != ProcessList.INVALID_ADJ
&& wasBackground == ActivityManager.isProcStateBackground(app.setProcState))) {
// Okay, it's unchanged, it won't impact any service it binds to, we're done here.
if (DEBUG_OOM_ADJ) {
@@ -965,7 +978,7 @@
if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) {
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
- app.cached = false;
+ app.setCached(false);
app.empty = false;
foregroundActivities = true;
}
@@ -990,7 +1003,7 @@
if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) {
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
- app.cached = false;
+ app.setCached(false);
app.empty = false;
foregroundActivities = true;
}
@@ -1022,7 +1035,7 @@
}
}
}
- app.cached = false;
+ app.setCached(false);
app.empty = false;
foregroundActivities = true;
}
@@ -1071,7 +1084,7 @@
app.adjSource = null;
app.adjTarget = null;
app.empty = false;
- app.cached = false;
+ app.setCached(false);
final int appUid = app.info.uid;
final int logUid = mService.mCurOomAdjUid;
@@ -1207,7 +1220,7 @@
// value that the caller wants us to.
adj = cachedAdj;
procState = PROCESS_STATE_CACHED_EMPTY;
- app.cached = true;
+ app.setCached(true);
app.empty = true;
app.adjType = "cch-empty";
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
@@ -1242,7 +1255,7 @@
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
procState = PROCESS_STATE_FOREGROUND_SERVICE;
app.adjType = "fg-service";
- app.cached = false;
+ app.setCached(false);
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + app.adjType + ": "
@@ -1252,7 +1265,7 @@
// The process is display an overlay UI.
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
procState = PROCESS_STATE_IMPORTANT_FOREGROUND;
- app.cached = false;
+ app.setCached(false);
app.adjType = "has-overlay-ui";
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
@@ -1282,7 +1295,7 @@
// thus out of background check), so we yes the best background level we can.
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
procState = PROCESS_STATE_TRANSIENT_BACKGROUND;
- app.cached = false;
+ app.setCached(false);
app.adjType = "force-imp";
app.adjSource = app.forcingToImportant;
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
@@ -1297,7 +1310,7 @@
// We don't want to kill the current heavy-weight process.
adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
- app.cached = false;
+ app.setCached(false);
app.adjType = "heavy";
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to heavy: " + app);
@@ -1318,7 +1331,7 @@
// home app, so we don't want to let it go into the background.
adj = ProcessList.HOME_APP_ADJ;
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
- app.cached = false;
+ app.setCached(false);
app.adjType = "home";
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to home: " + app);
@@ -1340,7 +1353,7 @@
// a good experience around switching between two apps.
adj = ProcessList.PREVIOUS_APP_ADJ;
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
- app.cached = false;
+ app.setCached(false);
app.adjType = "previous";
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to prev: " + app);
@@ -1387,7 +1400,7 @@
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to backup: " + app);
}
- app.cached = false;
+ app.setCached(false);
}
if (procState > ActivityManager.PROCESS_STATE_BACKUP) {
procState = ActivityManager.PROCESS_STATE_BACKUP;
@@ -1435,7 +1448,7 @@
reportOomAdjMessageLocked(TAG_OOM_ADJ,
"Raise adj to started service: " + app);
}
- app.cached = false;
+ app.setCached(false);
}
}
// If we have let the service slide into the background
@@ -1525,7 +1538,7 @@
if (adj > clientAdj) {
adjType = "cch-bound-ui-services";
}
- app.cached = false;
+ app.setCached(false);
clientAdj = adj;
clientProcState = procState;
} else {
@@ -1588,8 +1601,8 @@
newAdj = adj;
}
}
- if (!client.cached) {
- app.cached = false;
+ if (!client.isCached()) {
+ app.setCached(false);
}
if (adj > newAdj) {
adj = newAdj;
@@ -1631,7 +1644,7 @@
// Go at most to BOUND_TOP, unless requested to elevate
// to client's state.
clientProcState = PROCESS_STATE_BOUND_TOP;
- if (client.info.targetSdkVersion >= Build.VERSION_CODES.R) {
+ if (Compatibility.isChangeEnabled(PROCESS_CAPABILITY_CHANGE_ID)) {
if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
// TOP process passes all capabilities to the service.
capability = PROCESS_CAPABILITY_ALL;
@@ -1713,7 +1726,7 @@
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
}
- app.cached = false;
+ app.setCached(false);
app.adjType = "service";
app.adjTypeCode = ActivityManager.RunningAppProcessInfo
.REASON_SERVICE_IN_USE;
@@ -1778,7 +1791,7 @@
app.setCurRawAdj(adj);
adjType = "provider";
}
- app.cached &= client.cached;
+ app.setCached(app.isCached() & client.isCached());
}
if (clientProcState <= PROCESS_STATE_FOREGROUND_SERVICE) {
@@ -1823,7 +1836,7 @@
adj = ProcessList.FOREGROUND_APP_ADJ;
app.setCurRawAdj(adj);
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
- app.cached = false;
+ app.setCached(false);
app.adjType = "ext-provider";
app.adjTarget = cpr.name;
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
@@ -1847,7 +1860,7 @@
if (adj > ProcessList.PREVIOUS_APP_ADJ) {
adj = ProcessList.PREVIOUS_APP_ADJ;
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
- app.cached = false;
+ app.setCached(false);
app.adjType = "recent-provider";
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ,
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 7f9477ed..4a89845 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -91,9 +91,7 @@
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
import android.provider.DeviceConfig;
-import android.system.ErrnoException;
import android.system.Os;
-import android.system.OsConstants;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.EventLog;
@@ -327,12 +325,7 @@
/**
* How long between a process kill and we actually receive its death recipient
*/
- private static final long PROC_KILL_TIMEOUT = 2000; // 2 seconds;
-
- /**
- * How long between polls to check if the given process is dead or not.
- */
- private static final long PROC_DEATH_POLL_INTERVAL = 100;
+ private static final int PROC_KILL_TIMEOUT = 2000; // 2 seconds;
ActivityManagerService mService = null;
@@ -2169,28 +2162,6 @@
}
/**
- * A lite version of checking if a process is alive or not, by using kill(2) with signal 0.
- *
- * <p>
- * Note that, zombie processes are stil "alive" in this case, use the {@link
- * ActivityManagerService#isProcessAliveLocked} if zombie processes need to be excluded.
- * </p>
- */
- @GuardedBy("mService")
- private boolean isProcessAliveLiteLocked(ProcessRecord app) {
- // If somehow the pid is invalid, let's think it's dead.
- if (app.pid <= 0) {
- return false;
- }
- try {
- Os.kill(app.pid, 0);
- } catch (ErrnoException e) {
- return e.errno != OsConstants.ESRCH;
- }
- return true;
- }
-
- /**
* Kill (if asked to) and wait for the given process died if necessary
* @param app - The process record to kill
* @param doKill - Kill the given process record
@@ -2214,20 +2185,9 @@
// wait for the death
if (wait) {
- boolean isAlive = true;
- // ideally we should use pidfd_open(2) but it's available on kernel 5.3 or later
-
- final long timeout = SystemClock.uptimeMillis() + PROC_KILL_TIMEOUT;
- isAlive = isProcessAliveLiteLocked(app);
- while (timeout > SystemClock.uptimeMillis() && isAlive) {
- try {
- Thread.sleep(PROC_DEATH_POLL_INTERVAL);
- } catch (InterruptedException e) {
- }
- isAlive = isProcessAliveLiteLocked(app);
- }
-
- if (isAlive) {
+ try {
+ Process.waitForProcessDeath(app.pid, PROC_KILL_TIMEOUT);
+ } catch (Exception e) {
// Maybe the process goes into zombie, use an expensive API to check again.
if (mService.isProcessAliveLocked(app)) {
Slog.w(TAG, String.format(formatString,
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 0639db0..156466c 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -237,7 +237,7 @@
long lastTopTime; // The last time the process was in the TOP state or greater.
boolean reportLowMemory; // Set to true when waiting to report low mem
boolean empty; // Is this an empty background process?
- boolean cached; // Is this a cached process?
+ private volatile boolean mCached; // Is this a cached process?
String adjType; // Debugging: primary thing impacting oom_adj.
int adjTypeCode; // Debugging: adj code to report to app.
Object adjSource; // Debugging: option dependent object.
@@ -410,7 +410,7 @@
pw.println();
pw.print(prefix); pw.print("procStateMemTracker: ");
procStateMemTracker.dumpLine(pw);
- pw.print(prefix); pw.print("cached="); pw.print(cached);
+ pw.print(prefix); pw.print("cached="); pw.print(mCached);
pw.print(" empty="); pw.println(empty);
if (serviceb) {
pw.print(prefix); pw.print("serviceb="); pw.print(serviceb);
@@ -689,6 +689,18 @@
}
}
+ void setCached(boolean cached) {
+ if (mCached != cached) {
+ mCached = cached;
+ mWindowProcessController.onProcCachedStateChanged(cached);
+ }
+ }
+
+ @Override
+ public boolean isCached() {
+ return mCached;
+ }
+
boolean hasActivities() {
return mWindowProcessController.hasActivities();
}
diff --git a/services/core/java/com/android/server/location/ContextHubClientBroker.java b/services/core/java/com/android/server/location/ContextHubClientBroker.java
index 45d9bae..54f024f 100644
--- a/services/core/java/com/android/server/location/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/ContextHubClientBroker.java
@@ -16,6 +16,8 @@
package com.android.server.location;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
import android.Manifest;
import android.app.PendingIntent;
import android.content.Context;
@@ -109,6 +111,11 @@
private AtomicBoolean mIsPendingIntentCancelled = new AtomicBoolean(false);
/*
+ * True if the application creating the client has the ACCESS_CONTEXT_HUB permission.
+ */
+ private final boolean mHasAccessContextHubPermission;
+
+ /*
* Helper class to manage registered PendingIntent requests from the client.
*/
private class PendingIntentRequest {
@@ -165,6 +172,9 @@
mCallbackInterface = callback;
mPendingIntentRequest = new PendingIntentRequest();
mPackage = mContext.getPackageManager().getNameForUid(Binder.getCallingUid());
+
+ mHasAccessContextHubPermission = context.checkCallingPermission(
+ Manifest.permission.ACCESS_CONTEXT_HUB) == PERMISSION_GRANTED;
}
/* package */ ContextHubClientBroker(
@@ -178,6 +188,9 @@
mHostEndPointId = hostEndPointId;
mPendingIntentRequest = new PendingIntentRequest(pendingIntent, nanoAppId);
mPackage = pendingIntent.getCreatorPackage();
+
+ mHasAccessContextHubPermission = context.checkCallingPermission(
+ Manifest.permission.ACCESS_CONTEXT_HUB) == PERMISSION_GRANTED;
}
/**
@@ -415,10 +428,12 @@
*/
private void doSendPendingIntent(PendingIntent pendingIntent, Intent intent) {
try {
+ String requiredPermission = mHasAccessContextHubPermission
+ ? Manifest.permission.ACCESS_CONTEXT_HUB
+ : Manifest.permission.LOCATION_HARDWARE;
pendingIntent.send(
mContext, 0 /* code */, intent, null /* onFinished */, null /* Handler */,
- Manifest.permission.LOCATION_HARDWARE /* requiredPermission */,
- null /* options */);
+ requiredPermission, null /* options */);
} catch (PendingIntent.CanceledException e) {
mIsPendingIntentCancelled.set(true);
// The PendingIntent is no longer valid
diff --git a/services/core/java/com/android/server/location/ContextHubServiceUtil.java b/services/core/java/com/android/server/location/ContextHubServiceUtil.java
index 033437a..76cd9ce 100644
--- a/services/core/java/com/android/server/location/ContextHubServiceUtil.java
+++ b/services/core/java/com/android/server/location/ContextHubServiceUtil.java
@@ -16,6 +16,8 @@
package com.android.server.location;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
import android.Manifest;
import android.content.Context;
import android.hardware.contexthub.V1_0.ContextHub;
@@ -30,11 +32,10 @@
import android.hardware.location.NanoAppState;
import android.util.Log;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
-import java.util.ArrayList;
/**
* A class encapsulating helper functions used by the ContextHubService class
@@ -42,8 +43,7 @@
/* package */ class ContextHubServiceUtil {
private static final String TAG = "ContextHubServiceUtil";
private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE;
- private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '"
- + HARDWARE_PERMISSION + "' not granted to access ContextHub Hardware";
+ private static final String CONTEXT_HUB_PERMISSION = Manifest.permission.ACCESS_CONTEXT_HUB;
/**
* Creates a ConcurrentHashMap of the Context Hub ID to the ContextHubInfo object given an
@@ -200,7 +200,11 @@
*/
/* package */
static void checkPermissions(Context context) {
- context.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE);
+ if (context.checkCallingPermission(HARDWARE_PERMISSION) != PERMISSION_GRANTED
+ && context.checkCallingPermission(CONTEXT_HUB_PERMISSION) != PERMISSION_GRANTED) {
+ throw new SecurityException(
+ "LOCATION_HARDWARE or ACCESS_CONTEXT_HUB permission required to use Context Hub");
+ }
}
/**
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 767a1c0..d0e4fe6 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -51,6 +51,8 @@
import static android.content.Context.BIND_AUTO_CREATE;
import static android.content.Context.BIND_FOREGROUND_SERVICE;
import static android.content.Context.BIND_NOT_PERCEPTIBLE;
+import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC;
+import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED;
import static android.content.pm.PackageManager.FEATURE_LEANBACK;
import static android.content.pm.PackageManager.FEATURE_TELEVISION;
import static android.content.pm.PackageManager.MATCH_ALL;
@@ -147,10 +149,12 @@
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
+import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
+import android.content.pm.ShortcutInfo;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.database.ContentObserver;
@@ -279,6 +283,7 @@
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
@@ -399,6 +404,7 @@
private RoleObserver mRoleObserver;
private UserManager mUm;
private IPlatformCompat mPlatformCompat;
+ private LauncherApps mLauncherAppsService;
final IBinder mForegroundToken = new Binder();
private WorkerHandler mHandler;
@@ -1199,12 +1205,7 @@
final StatusBarNotification n = r.sbn;
final int callingUid = n.getUid();
final String pkg = n.getPackageName();
- if (isBubble && isNotificationAppropriateToBubble(r, pkg, callingUid,
- null /* oldEntry */)) {
- r.getNotification().flags |= FLAG_BUBBLE;
- } else {
- r.getNotification().flags &= ~FLAG_BUBBLE;
- }
+ applyFlagBubble(r, pkg, callingUid, null /* oldEntry */, isBubble);
}
}
}
@@ -1579,6 +1580,80 @@
}
};
+ // Key: packageName Value: <shortcutId, notifId>
+ private HashMap<String, HashMap<String, String>> mActiveShortcutBubbles = new HashMap<>();
+
+ private boolean mLauncherAppsCallbackRegistered;
+
+ // Bubbles can be created based on a shortcut, we need to listen for changes to
+ // that shortcut so that we may update the bubble appropriately.
+ private final LauncherApps.Callback mLauncherAppsCallback = new LauncherApps.Callback() {
+ @Override
+ public void onPackageRemoved(String packageName, UserHandle user) {
+ }
+
+ @Override
+ public void onPackageAdded(String packageName, UserHandle user) {
+ }
+
+ @Override
+ public void onPackageChanged(String packageName, UserHandle user) {
+ }
+
+ @Override
+ public void onPackagesAvailable(String[] packageNames, UserHandle user,
+ boolean replacing) {
+ }
+
+ @Override
+ public void onPackagesUnavailable(String[] packageNames, UserHandle user,
+ boolean replacing) {
+ }
+
+ @Override
+ public void onShortcutsChanged(@NonNull String packageName,
+ @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
+ HashMap<String, String> shortcutBubbles = mActiveShortcutBubbles.get(packageName);
+ boolean isAppForeground = packageName != null
+ && mActivityManager.getPackageImportance(packageName) == IMPORTANCE_FOREGROUND;
+ ArrayList<String> bubbleKeysToRemove = new ArrayList<>();
+ if (shortcutBubbles != null) {
+ // If we can't find one of our bubbles in the shortcut list, that bubble needs
+ // to be removed.
+ for (String shortcutId : shortcutBubbles.keySet()) {
+ boolean foundShortcut = false;
+ for (int i = 0; i < shortcuts.size(); i++) {
+ if (shortcuts.get(i).getId().equals(shortcutId)) {
+ foundShortcut = true;
+ break;
+ }
+ }
+ if (!foundShortcut) {
+ bubbleKeysToRemove.add(shortcutBubbles.get(shortcutId));
+ }
+ }
+ }
+
+ // Do the removals
+ for (int i = 0; i < bubbleKeysToRemove.size(); i++) {
+ // update flag bubble
+ String bubbleKey = bubbleKeysToRemove.get(i);
+ synchronized (mNotificationLock) {
+ NotificationRecord r = mNotificationsByKey.get(bubbleKey);
+ if (r != null) {
+ final StatusBarNotification n = r.sbn;
+ final int callingUid = n.getUid();
+ final String pkg = n.getPackageName();
+ applyFlagBubble(r, pkg, callingUid, null /* oldEntry */, isAppForeground);
+ mHandler.post(new EnqueueNotificationRunnable(user.getIdentifier(), r,
+ false /* isAppForeground */));
+ }
+ }
+ }
+ }
+ };
+
+
private final class SettingsObserver extends ContentObserver {
private final Uri NOTIFICATION_BADGING_URI
= Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
@@ -1662,6 +1737,11 @@
}
@VisibleForTesting
+ void setLauncherApps(LauncherApps launcherApps) {
+ mLauncherAppsService = launcherApps;
+ }
+
+ @VisibleForTesting
void setHints(int hints) {
mListenerHints = hints;
}
@@ -2155,6 +2235,8 @@
mRoleObserver = new RoleObserver(getContext().getSystemService(RoleManager.class),
mPackageManager, getContext().getMainExecutor());
mRoleObserver.init();
+ mLauncherAppsService =
+ (LauncherApps) getContext().getSystemService(Context.LAUNCHER_APPS_SERVICE);
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
// This observer will force an update when observe is called, causing us to
// bind to listener services.
@@ -5444,19 +5526,18 @@
}
/**
- * Updates the flags for this notification to reflect whether it is a bubble or not.
+ * Updates the flags for this notification to reflect whether it is a bubble or not. Some
+ * bubble specific flags only work if the app is foreground, this will strip those flags
+ * if the app wasn't foreground.
*/
- private void flagNotificationForBubbles(NotificationRecord r, String pkg, int userId,
+ private void updateNotificationBubbleFlags(NotificationRecord r, String pkg, int userId,
NotificationRecord oldRecord, boolean isAppForeground) {
Notification notification = r.getNotification();
- if (isNotificationAppropriateToBubble(r, pkg, userId, oldRecord)) {
- notification.flags |= FLAG_BUBBLE;
- } else {
- notification.flags &= ~FLAG_BUBBLE;
- }
+ applyFlagBubble(r, pkg, userId, oldRecord, true /* desiredFlag */);
+
+ // Remove any bubble specific flags that only work when foregrounded
Notification.BubbleMetadata metadata = notification.getBubbleMetadata();
if (!isAppForeground && metadata != null) {
- // Remove any flags that only work when foregrounded
int flags = metadata.getFlags();
flags &= ~Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE;
flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
@@ -5465,6 +5546,54 @@
}
/**
+ * Handles actually applying or removing {@link Notification#FLAG_BUBBLE}. Performs necessary
+ * checks for the provided record to see if it can actually be a bubble.
+ * Tracks shortcut based bubbles so that we can find out if they've changed or been removed.
+ */
+ private void applyFlagBubble(NotificationRecord r, String pkg, int userId,
+ NotificationRecord oldRecord, boolean desiredFlag) {
+ boolean applyFlag = desiredFlag
+ && isNotificationAppropriateToBubble(r, pkg, userId, oldRecord);
+ final String shortcutId = r.getNotification().getBubbleMetadata() != null
+ ? r.getNotification().getBubbleMetadata().getShortcutId()
+ : null;
+ if (applyFlag) {
+ if (shortcutId != null) {
+ // Must track shortcut based bubbles in case the shortcut is removed
+ HashMap<String, String> packageBubbles = mActiveShortcutBubbles.get(
+ r.sbn.getPackageName());
+ if (packageBubbles == null) {
+ packageBubbles = new HashMap<>();
+ }
+ packageBubbles.put(shortcutId, r.getKey());
+ mActiveShortcutBubbles.put(r.sbn.getPackageName(), packageBubbles);
+ if (!mLauncherAppsCallbackRegistered) {
+ mLauncherAppsService.registerCallback(mLauncherAppsCallback, mHandler);
+ mLauncherAppsCallbackRegistered = true;
+ }
+ }
+ r.getNotification().flags |= FLAG_BUBBLE;
+ } else {
+ if (shortcutId != null) {
+ // No longer track shortcut
+ HashMap<String, String> packageBubbles = mActiveShortcutBubbles.get(
+ r.sbn.getPackageName());
+ if (packageBubbles != null) {
+ packageBubbles.remove(shortcutId);
+ }
+ if (packageBubbles != null && packageBubbles.isEmpty()) {
+ mActiveShortcutBubbles.remove(r.sbn.getPackageName());
+ }
+ if (mLauncherAppsCallbackRegistered && mActiveShortcutBubbles.isEmpty()) {
+ mLauncherAppsService.unregisterCallback(mLauncherAppsCallback);
+ mLauncherAppsCallbackRegistered = false;
+ }
+ }
+ r.getNotification().flags &= ~FLAG_BUBBLE;
+ }
+ }
+
+ /**
* @return whether the provided notification record is allowed to be represented as a bubble,
* accounting for user choice & policy.
*/
@@ -5538,10 +5667,6 @@
// no log: no need to inform dev if they didn't attach bubble metadata
return false;
}
- if (!canLaunchInActivityView(getContext(), metadata.getIntent(), pkg)) {
- // no log: method has the failure log
- return false;
- }
if (!mPreferencesHelper.bubblesEnabled()) {
logBubbleError(r.getKey(), "bubbles disabled for user: " + userId);
return false;
@@ -5556,7 +5681,20 @@
"bubbles for channel " + r.getChannel().getId() + " disabled");
return false;
}
- return true;
+
+ String shortcutId = metadata.getShortcutId();
+ boolean shortcutValid = shortcutId != null
+ && hasValidShortcutInfo(shortcutId, pkg, r.getUser());
+ if (metadata.getBubbleIntent() == null && !shortcutValid) {
+ // Should have a shortcut if intent is null
+ logBubbleError(r.getKey(), "couldn't find shortcutId for bubble: " + shortcutId);
+ return false;
+ }
+ if (shortcutValid) {
+ return true;
+ }
+ // no log: canLaunch method has the failure log
+ return canLaunchInActivityView(getContext(), metadata.getBubbleIntent(), pkg);
}
private boolean hasValidRemoteInput(Notification n) {
@@ -5575,6 +5713,22 @@
return false;
}
+ private boolean hasValidShortcutInfo(String shortcutId, String packageName, UserHandle user) {
+ LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery();
+ if (packageName != null) {
+ query.setPackage(packageName);
+ }
+ if (shortcutId != null) {
+ query.setShortcutIds(Arrays.asList(shortcutId));
+ }
+ query.setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED);
+ List<ShortcutInfo> shortcuts = mLauncherAppsService.getShortcuts(query, user);
+ ShortcutInfo shortcutInfo = shortcuts != null && shortcuts.size() > 0
+ ? shortcuts.get(0)
+ : null;
+ return shortcutInfo != null;
+ }
+
private void logBubbleError(String key, String failureMessage) {
if (DBG) {
Log.w(TAG, "Bubble notification: " + key + " failed: " + failureMessage);
@@ -6030,7 +6184,7 @@
final String tag = n.getTag();
// We need to fix the notification up a little for bubbles
- flagNotificationForBubbles(r, pkg, callingUid, old, isAppForeground);
+ updateNotificationBubbleFlags(r, pkg, callingUid, old, isAppForeground);
// Handle grouped notifications and bail out early if we
// can to avoid extracting signals.
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index c8afcc9..f344a84 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -466,6 +466,7 @@
pw.println(prefix + "deleteIntent=" + notification.deleteIntent);
pw.println(prefix + "number=" + notification.number);
pw.println(prefix + "groupAlertBehavior=" + notification.getGroupAlertBehavior());
+ pw.println(prefix + "when=" + notification.when);
pw.print(prefix + "tickerText=");
if (!TextUtils.isEmpty(notification.tickerText)) {
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index c36d5ef..7164a30 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -24,8 +24,11 @@
import android.os.IRecoverySystem;
import android.os.IRecoverySystemProgressListener;
import android.os.PowerManager;
+import android.os.Process;
import android.os.RecoverySystem;
import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
import android.os.SystemProperties;
import android.util.Slog;
@@ -39,6 +42,7 @@
import java.io.DataInputStream;
import java.io.DataOutputStream;
+import java.io.FileDescriptor;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@@ -550,4 +554,28 @@
IoUtils.closeQuietly(mLocalSocket);
}
}
+
+ private boolean isCallerShell() {
+ final int callingUid = Binder.getCallingUid();
+ return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
+ }
+
+ private void enforceShell() {
+ if (!isCallerShell()) {
+ throw new SecurityException("Caller must be shell");
+ }
+ }
+
+ @Override
+ public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+ String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
+ enforceShell();
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ new RecoverySystemShellCommand(this).exec(
+ this, in, out, err, args, callback, resultReceiver);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java
new file mode 100644
index 0000000..c6905b5
--- /dev/null
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.recoverysystem;
+
+import android.os.IRecoverySystem;
+import android.os.RemoteException;
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+
+/**
+ * Shell commands to call to {@link RecoverySystemService} from ADB.
+ */
+public class RecoverySystemShellCommand extends ShellCommand {
+ private final IRecoverySystem mService;
+
+ public RecoverySystemShellCommand(RecoverySystemService service) {
+ mService = service;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+ try {
+ switch (cmd) {
+ case "request-lskf":
+ return requestLskf();
+ case "clear-lskf":
+ return clearLskf();
+ case "reboot-and-apply":
+ return rebootAndApply();
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ } catch (Exception e) {
+ getErrPrintWriter().println("Error while executing command: " + cmd);
+ e.printStackTrace(getErrPrintWriter());
+ return -1;
+ }
+ }
+
+ private int requestLskf() throws RemoteException {
+ String updateToken = getNextArgRequired();
+ boolean success = mService.requestLskf(updateToken, null);
+ PrintWriter pw = getOutPrintWriter();
+ pw.println("Request LSKF status: " + (success ? "success" : "failure"));
+ return 0;
+ }
+
+ private int clearLskf() throws RemoteException {
+ boolean success = mService.clearLskf();
+ PrintWriter pw = getOutPrintWriter();
+ pw.println("Clear LSKF: " + (success ? "success" : "failure"));
+ return 0;
+ }
+
+ private int rebootAndApply() throws RemoteException {
+ String updateToken = getNextArgRequired();
+ String rebootReason = getNextArgRequired();
+ boolean success = mService.rebootWithLskf(updateToken, rebootReason);
+ PrintWriter pw = getOutPrintWriter();
+ pw.println("Reboot and apply status: " + (success ? "success" : "failure"));
+ return 0;
+ }
+
+ @Override
+ public void onHelp() {
+ PrintWriter pw = getOutPrintWriter();
+ pw.println("Recovery system commands:");
+ pw.println(" request-lskf <token>");
+ pw.println(" clear-lskf");
+ pw.println(" reboot-and-apply <token> <reason>");
+ }
+}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 6418b2c..3c41c10 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -196,16 +196,23 @@
private final Object mNetworkStatsLock = new Object();
@GuardedBy("mNetworkStatsLock")
private INetworkStatsService mNetworkStatsService;
+
private final Object mThermalLock = new Object();
@GuardedBy("mThermalLock")
private IThermalService mThermalService;
+
private final Object mStoragedLock = new Object();
@GuardedBy("mStoragedLock")
private IStoraged mStorageService;
+
private final Object mNotificationStatsLock = new Object();
@GuardedBy("mNotificationStatsLock")
private INotificationManager mNotificationManagerService;
+ private final Object mProcessStatsLock = new Object();
+ @GuardedBy("mProcessStatsLock")
+ private IProcessStats mProcessStatsService;
+
private final Context mContext;
private StatsManager mStatsManager;
private StorageManager mStorageManager;
@@ -222,7 +229,7 @@
mTelephony = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
mStorageManager = (StorageManager) mContext.getSystemService(StorageManager.class);
- // Used to initialize the CPU Frequency atom.
+ // Initialize state for CPU_TIME_PER_FREQ atom
PowerProfile powerProfile = new PowerProfile(mContext);
final int numClusters = powerProfile.getNumCpuClusters();
mKernelCpuSpeedReaders = new KernelCpuSpeedReader[numClusters];
@@ -237,6 +244,9 @@
// Used for CPU_TIME_PER_THREAD_FREQ
mKernelCpuThreadReader =
KernelCpuThreadReaderSettingsObserver.getSettingsModifiedReader(mContext);
+
+ // Used by PROC_STATS and PROC_STATS_PKG_PROC atoms
+ mBaseDir.mkdirs();
}
@Override
@@ -385,7 +395,7 @@
synchronized (mNotificationStatsLock) {
if (mNotificationManagerService == null) {
mNotificationManagerService = INotificationManager.Stub.asInterface(
- ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
}
if (mNotificationManagerService != null) {
try {
@@ -403,6 +413,28 @@
return mNotificationManagerService;
}
+ private IProcessStats getIProcessStatsService() {
+ synchronized (mProcessStatsLock) {
+ if (mProcessStatsService == null) {
+ mProcessStatsService = IProcessStats.Stub.asInterface(
+ ServiceManager.getService(ProcessStats.SERVICE_NAME));
+ }
+ if (mProcessStatsService != null) {
+ try {
+ mProcessStatsService.asBinder().linkToDeath(() -> {
+ synchronized (mProcessStatsLock) {
+ mProcessStatsService = null;
+ }
+ }, /* flags */ 0);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "linkToDeath with ProcessStats failed", e);
+ mProcessStatsService = null;
+ }
+ }
+ }
+ return mProcessStatsService;
+ }
+
private void registerWifiBytesTransfer() {
int tagId = StatsLog.WIFI_BYTES_TRANSFER;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
@@ -1868,22 +1900,88 @@
return StatsManager.PULL_SUCCESS;
}
- private void registerProcStats() {
- // No op.
- }
+ private File mBaseDir = new File(SystemServiceManager.ensureSystemDir(), "stats_companion");
- private void pullProcStats() {
- // No op.
+ private void registerProcStats() {
+ int tagId = StatsLog.PROC_STATS;
+ mStatsManager.registerPullAtomCallback(
+ tagId,
+ null, // use default PullAtomMetadata values
+ (atomTag, data) -> pullProcStats(ProcessStats.REPORT_ALL, atomTag, data),
+ BackgroundThread.getExecutor()
+ );
}
private void registerProcStatsPkgProc() {
- // No op.
+ int tagId = StatsLog.PROC_STATS_PKG_PROC;
+ mStatsManager.registerPullAtomCallback(
+ tagId,
+ null, // use default PullAtomMetadata values
+ (atomTag, data) -> pullProcStats(ProcessStats.REPORT_PKG_PROC_STATS, atomTag, data),
+ BackgroundThread.getExecutor()
+ );
}
- private void pullProcStatsPkgProc() {
- // No op.
+ private int pullProcStats(int section, int atomTag, List<StatsEvent> pulledData) {
+ IProcessStats processStatsService = getIProcessStatsService();
+ if (processStatsService == null) {
+ return StatsManager.PULL_SKIP;
+ }
+
+ synchronized (mProcessStatsLock) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ long lastHighWaterMark = readProcStatsHighWaterMark(section);
+ List<ParcelFileDescriptor> statsFiles = new ArrayList<>();
+ long highWaterMark = processStatsService.getCommittedStats(
+ lastHighWaterMark, section, true, statsFiles);
+ if (statsFiles.size() != 1) {
+ return StatsManager.PULL_SKIP;
+ }
+ unpackStreamedData(atomTag, pulledData, statsFiles);
+ new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + lastHighWaterMark)
+ .delete();
+ new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + highWaterMark)
+ .createNewFile();
+ } catch (IOException e) {
+ Slog.e(TAG, "Getting procstats failed: ", e);
+ return StatsManager.PULL_SKIP;
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Getting procstats failed: ", e);
+ return StatsManager.PULL_SKIP;
+ } catch (SecurityException e) {
+ Slog.e(TAG, "Getting procstats failed: ", e);
+ return StatsManager.PULL_SKIP;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ return StatsManager.PULL_SUCCESS;
}
+ // read high watermark for section
+ private long readProcStatsHighWaterMark(int section) {
+ try {
+ File[] files = mBaseDir.listFiles((d, name) -> {
+ return name.toLowerCase().startsWith(String.valueOf(section) + '_');
+ });
+ if (files == null || files.length == 0) {
+ return 0;
+ }
+ if (files.length > 1) {
+ Slog.e(TAG, "Only 1 file expected for high water mark. Found " + files.length);
+ }
+ return Long.valueOf(files[0].getName().split("_")[1]);
+ } catch (SecurityException e) {
+ Slog.e(TAG, "Failed to get procstats high watermark file.", e);
+ } catch (NumberFormatException e) {
+ Slog.e(TAG, "Failed to parse file name.", e);
+ }
+ return 0;
+ }
+
+
private StoragedUidIoStatsReader mStoragedUidIoStatsReader =
new StoragedUidIoStatsReader();
@@ -1953,7 +2051,7 @@
private void registerProcessCpuTime() {
int tagId = StatsLog.PROCESS_CPU_TIME;
- // Min cool-down is 5 sec, inline with what ActivityManagerService uses.
+ // Min cool-down is 5 sec, in line with what ActivityManagerService uses.
PullAtomMetadata metadata = PullAtomMetadata.newBuilder()
.setCoolDownNs(5 * NS_PER_SEC)
.build();
@@ -2562,7 +2660,7 @@
}
private int pullAppOps(int atomTag, List<StatsEvent> pulledData) {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
@@ -2678,7 +2776,7 @@
}
final long callingToken = Binder.clearCallingIdentity();
try {
- // determine last pull tine. Copy file trick from pullProcessStats?
+ // determine last pull tine. Copy file trick from pullProcStats?
long wallClockNanos = SystemClock.currentTimeMicro() * 1000L;
long lastNotificationStatsNs = wallClockNanos -
TimeUnit.NANOSECONDS.convert(1, TimeUnit.DAYS);
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 812942e..87b04b2 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -179,6 +179,8 @@
// Last configuration that was reported to the process.
private final Configuration mLastReportedConfiguration;
+ // Configuration that is waiting to be dispatched to the process.
+ private Configuration mPendingConfiguration;
private final Configuration mNewOverrideConfig = new Configuration();
// Registered display id as a listener to override config change
private int mDisplayId;
@@ -1073,24 +1075,38 @@
return;
}
- try {
- if (mThread == null) {
- if (Build.IS_DEBUGGABLE && mIsImeProcess) {
- // TODO (b/135719017): Temporary log for debugging IME service.
- Slog.w(TAG_CONFIGURATION, "Unable to send config for IME proc " + mName
- + ": no app thread");
- }
- return;
+ if (mListener.isCached()) {
+ // This process is in a cached state. We will delay delivering the config change to the
+ // process until the process is no longer cached.
+ if (mPendingConfiguration == null) {
+ mPendingConfiguration = new Configuration(config);
+ } else {
+ mPendingConfiguration.setTo(config);
}
- if (DEBUG_CONFIGURATION) {
- Slog.v(TAG_CONFIGURATION, "Sending to proc " + mName
- + " new config " + config);
- }
+ return;
+ }
+
+ dispatchConfigurationChange(config);
+ }
+
+ private void dispatchConfigurationChange(Configuration config) {
+ if (mThread == null) {
if (Build.IS_DEBUGGABLE && mIsImeProcess) {
// TODO (b/135719017): Temporary log for debugging IME service.
- Slog.v(TAG_CONFIGURATION, "Sending to IME proc " + mName
- + " new config " + config);
+ Slog.w(TAG_CONFIGURATION, "Unable to send config for IME proc " + mName
+ + ": no app thread");
}
+ return;
+ }
+ if (DEBUG_CONFIGURATION) {
+ Slog.v(TAG_CONFIGURATION, "Sending to proc " + mName + " new config " + config);
+ }
+ if (Build.IS_DEBUGGABLE && mIsImeProcess) {
+ // TODO (b/135719017): Temporary log for debugging IME service.
+ Slog.v(TAG_CONFIGURATION, "Sending to IME proc " + mName + " new config " + config);
+ }
+
+ try {
config.seq = mAtm.increaseConfigurationSeqLocked();
mAtm.getLifecycleManager().scheduleTransaction(mThread,
ConfigurationChangeItem.obtain(config));
@@ -1190,6 +1206,21 @@
return false;
}
+ /**
+ * Called to notify WindowProcessController of a change in the process's cached state.
+ *
+ * @param isCached whether or not the process is cached.
+ */
+ public void onProcCachedStateChanged(boolean isCached) {
+ synchronized (mAtm.mGlobalLock) {
+ if (!isCached && mPendingConfiguration != null) {
+ final Configuration config = mPendingConfiguration;
+ mPendingConfiguration = null;
+ dispatchConfigurationChange(config);
+ }
+ }
+ }
+
@HotPath(caller = HotPath.OOM_ADJUSTMENT)
public void onTopProcChanged() {
synchronized (mAtm.mGlobalLockWithoutBoost) {
diff --git a/services/core/java/com/android/server/wm/WindowProcessListener.java b/services/core/java/com/android/server/wm/WindowProcessListener.java
index 9505191..88c215b 100644
--- a/services/core/java/com/android/server/wm/WindowProcessListener.java
+++ b/services/core/java/com/android/server/wm/WindowProcessListener.java
@@ -51,6 +51,11 @@
*/
boolean isRemoved();
+ /**
+ * Returns true if the process is in a cached state.
+ */
+ boolean isCached();
+
/** Returns the total time (in milliseconds) spent executing in both user and system code. */
long getCpuTime();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e939d84..0c79a6f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -370,6 +370,8 @@
private static final String TAG_PROTECTED_PACKAGES = "protected-packages";
+ private static final String TAG_SECONDARY_LOCK_SCREEN = "secondary-lock-screen";
+
private static final int REQUEST_EXPIRE_PASSWORD = 5571;
private static final long MS_PER_DAY = TimeUnit.DAYS.toMillis(1);
@@ -771,6 +773,8 @@
boolean mCurrentInputMethodSet = false;
+ boolean mSecondaryLockscreenEnabled = false;
+
// TODO(b/35385311): Keep track of metadata in TrustedCertificateStore instead.
Set<String> mOwnerInstalledCaCerts = new ArraySet<>();
@@ -3322,6 +3326,12 @@
out.endTag(null, TAG_LOCK_TASK_FEATURES);
}
+ if (policy.mSecondaryLockscreenEnabled) {
+ out.startTag(null, TAG_SECONDARY_LOCK_SCREEN);
+ out.attribute(null, ATTR_VALUE, Boolean.toString(true));
+ out.endTag(null, TAG_SECONDARY_LOCK_SCREEN);
+ }
+
if (policy.mStatusBarDisabled) {
out.startTag(null, TAG_STATUS_BAR);
out.attribute(null, ATTR_DISABLED, Boolean.toString(policy.mStatusBarDisabled));
@@ -3571,6 +3581,9 @@
} else if (TAG_LOCK_TASK_FEATURES.equals(tag)) {
policy.mLockTaskFeatures = Integer.parseInt(
parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_SECONDARY_LOCK_SCREEN.equals(tag)) {
+ policy.mSecondaryLockscreenEnabled = Boolean.parseBoolean(
+ parser.getAttributeValue(null, ATTR_VALUE));
} else if (TAG_STATUS_BAR.equals(tag)) {
policy.mStatusBarDisabled = Boolean.parseBoolean(
parser.getAttributeValue(null, ATTR_DISABLED));
@@ -8601,6 +8614,7 @@
// Clear delegations.
policy.mDelegationMap.clear();
policy.mStatusBarDisabled = false;
+ policy.mSecondaryLockscreenEnabled = false;
policy.mUserProvisioningState = DevicePolicyManager.STATE_USER_UNMANAGED;
policy.mAffiliationIds.clear();
policy.mLockTaskPackages.clear();
@@ -11154,6 +11168,33 @@
}
@Override
+ public void setSecondaryLockscreenEnabled(ComponentName who, boolean enabled) {
+ enforceCanSetSecondaryLockscreenEnabled(who);
+ synchronized (getLockObject()) {
+ final int userId = mInjector.userHandleGetCallingUserId();
+ DevicePolicyData policy = getUserData(userId);
+ policy.mSecondaryLockscreenEnabled = enabled;
+ saveSettingsLocked(userId);
+ }
+ }
+
+ @Override
+ public boolean isSecondaryLockscreenEnabled(int userId) {
+ synchronized (getLockObject()) {
+ return getUserData(userId).mSecondaryLockscreenEnabled;
+ }
+ }
+
+ private void enforceCanSetSecondaryLockscreenEnabled(ComponentName who) {
+ enforceProfileOrDeviceOwner(who);
+ final int userId = mInjector.userHandleGetCallingUserId();
+ if (isManagedProfile(userId)) {
+ throw new SecurityException(
+ "User " + userId + " is not allowed to call setSecondaryLockscreenEnabled");
+ }
+ }
+
+ @Override
public void setLockTaskPackages(ComponentName who, String[] packages)
throws SecurityException {
Objects.requireNonNull(who, "ComponentName is null");
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 0b7c359..258d762 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -223,14 +223,8 @@
"com.android.server.usb.UsbService$Lifecycle";
private static final String MIDI_SERVICE_CLASS =
"com.android.server.midi.MidiService$Lifecycle";
- private static final String WIFI_APEX_SERVICE_JAR_PATH =
- "/apex/com.android.wifi/javalib/wifi-service.jar";
private static final String WIFI_SERVICE_CLASS =
"com.android.server.wifi.WifiService";
- private static final String WIFI_SCANNING_SERVICE_CLASS =
- "com.android.server.wifi.scanner.WifiScanningService";
- private static final String WIFI_RTT_SERVICE_CLASS =
- "com.android.server.wifi.rtt.RttService";
private static final String WIFI_AWARE_SERVICE_CLASS =
"com.android.server.wifi.aware.WifiAwareService";
private static final String WIFI_P2P_SERVICE_CLASS =
@@ -1437,36 +1431,33 @@
PackageManager.FEATURE_WIFI)) {
// Wifi Service must be started first for wifi-related services.
t.traceBegin("StartWifi");
- mSystemServiceManager.startServiceFromJar(
- WIFI_SERVICE_CLASS, WIFI_APEX_SERVICE_JAR_PATH);
+ mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
t.traceEnd();
t.traceBegin("StartWifiScanning");
- mSystemServiceManager.startServiceFromJar(
- WIFI_SCANNING_SERVICE_CLASS, WIFI_APEX_SERVICE_JAR_PATH);
+ mSystemServiceManager.startService(
+ "com.android.server.wifi.scanner.WifiScanningService");
t.traceEnd();
}
if (context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_WIFI_RTT)) {
t.traceBegin("StartRttService");
- mSystemServiceManager.startServiceFromJar(
- WIFI_RTT_SERVICE_CLASS, WIFI_APEX_SERVICE_JAR_PATH);
+ mSystemServiceManager.startService(
+ "com.android.server.wifi.rtt.RttService");
t.traceEnd();
}
if (context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_WIFI_AWARE)) {
t.traceBegin("StartWifiAware");
- mSystemServiceManager.startServiceFromJar(
- WIFI_AWARE_SERVICE_CLASS, WIFI_APEX_SERVICE_JAR_PATH);
+ mSystemServiceManager.startService(WIFI_AWARE_SERVICE_CLASS);
t.traceEnd();
}
if (context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_WIFI_DIRECT)) {
t.traceBegin("StartWifiP2P");
- mSystemServiceManager.startServiceFromJar(
- WIFI_P2P_SERVICE_CLASS, WIFI_APEX_SERVICE_JAR_PATH);
+ mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS);
t.traceEnd();
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 4635c08..fc2ae40 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -546,7 +546,7 @@
public void testUpdateOomAdj_DoOne_NonCachedToCached() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
- app.cached = false;
+ app.setCached(false);
app.setCurRawAdj(SERVICE_ADJ);
doReturn(null).when(sService).getTopAppLocked();
sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
@@ -1662,7 +1662,7 @@
}
app.lastProviderTime = lastProviderTime;
app.lastTopTime = lastTopTime;
- app.cached = cached;
+ app.setCached(cached);
for (int i = 0; i < numOfExecutingServices; i++) {
app.executingServices.add(mock(ServiceRecord.class));
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index aeba488..8f1d0f7 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4189,6 +4189,52 @@
() -> dpm.setLockTaskFeatures(admin1, flags));
}
+ public void testSecondaryLockscreen_profileOwner() throws Exception {
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+ // Initial state is disabled.
+ assertFalse(dpm.isSecondaryLockscreenEnabled(DpmMockContext.CALLER_USER_HANDLE));
+
+ // Profile owner can set enabled state.
+ setAsProfileOwner(admin1);
+ dpm.setSecondaryLockscreenEnabled(admin1, true);
+ assertTrue(dpm.isSecondaryLockscreenEnabled(DpmMockContext.CALLER_USER_HANDLE));
+
+ // Managed profile managed by different package is unaffiliated - cannot set enabled.
+ final int managedProfileUserId = 15;
+ final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 20456);
+ final ComponentName adminDifferentPackage =
+ new ComponentName("another.package", "whatever.class");
+ addManagedProfile(adminDifferentPackage, managedProfileAdminUid, admin2);
+ mContext.binder.callingUid = managedProfileAdminUid;
+ assertExpectException(SecurityException.class, /* messageRegex= */ null,
+ () -> dpm.setSecondaryLockscreenEnabled(adminDifferentPackage, false));
+ }
+
+ public void testSecondaryLockscreen_deviceOwner() throws Exception {
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+ // Initial state is disabled.
+ assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.USER_SYSTEM));
+
+ // Device owners can set enabled state.
+ setupDeviceOwner();
+ dpm.setSecondaryLockscreenEnabled(admin1, true);
+ assertTrue(dpm.isSecondaryLockscreenEnabled(UserHandle.USER_SYSTEM));
+ }
+
+ public void testSecondaryLockscreen_nonOwner() throws Exception {
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+ // Initial state is disabled.
+ assertFalse(dpm.isSecondaryLockscreenEnabled(DpmMockContext.CALLER_USER_HANDLE));
+
+ // Non-DO/PO cannot set enabled state.
+ assertExpectException(SecurityException.class, /* messageRegex= */ null,
+ () -> dpm.setSecondaryLockscreenEnabled(admin1, true));
+ assertFalse(dpm.isSecondaryLockscreenEnabled(DpmMockContext.CALLER_USER_HANDLE));
+ }
+
public void testIsDeviceManaged() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
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 bc2fbc6..9260fbf 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -100,8 +100,10 @@
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
+import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
+import android.content.pm.ShortcutInfo;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Color;
@@ -214,6 +216,8 @@
@Mock
private AudioManager mAudioManager;
@Mock
+ private LauncherApps mLauncherApps;
+ @Mock
ActivityManager mActivityManager;
@Mock
Resources mResources;
@@ -420,6 +424,7 @@
mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
mService.setAudioManager(mAudioManager);
+ mService.setLauncherApps(mLauncherApps);
// Tests call directly into the Binder.
mBinderService = mService.getBinderService();
@@ -618,8 +623,8 @@
private Notification.BubbleMetadata.Builder getBubbleMetadataBuilder() {
PendingIntent pi = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
return new Notification.BubbleMetadata.Builder()
- .setIntent(pi)
- .setIcon(Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon));
+ .createIntentBubble(pi,
+ Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon));
}
private Notification.Builder getMessageStyleNotifBuilder(boolean addBubbleMetadata,
@@ -5689,6 +5694,58 @@
}
@Test
+ public void testNotificationBubbles_flagRemoved_whenShortcutRemoved()
+ throws RemoteException {
+ // Bubbles are allowed!
+ setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */);
+
+ ArgumentCaptor<LauncherApps.Callback> launcherAppsCallback =
+ ArgumentCaptor.forClass(LauncherApps.Callback.class);
+
+ // Messaging notification with shortcut info
+ Notification.BubbleMetadata metadata =
+ getBubbleMetadataBuilder().createShortcutBubble("someshortcutId").build();
+ Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
+ null /* groupKey */, false /* isSummary */);
+ nb.setBubbleMetadata(metadata);
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
+ "tag", mUid, 0, nb.build(), new UserHandle(mUid), null, 0);
+ NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ // Pretend the shortcut exists
+ List<ShortcutInfo> shortcutInfos = new ArrayList<>();
+ shortcutInfos.add(mock(ShortcutInfo.class));
+ when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
+
+ // Test: Send the bubble notification
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.sbn.getTag(),
+ nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId());
+ waitForIdle();
+
+ // Verify:
+
+ // Make sure we register the callback for shortcut changes
+ verify(mLauncherApps, times(1)).registerCallback(launcherAppsCallback.capture(), any());
+
+ // yes allowed, yes messaging w/shortcut, yes bubble
+ Notification notif = mService.getNotificationRecord(nr.sbn.getKey()).getNotification();
+ assertTrue(notif.isBubbleNotification());
+
+ // Test: Remove the shortcut
+ launcherAppsCallback.getValue().onShortcutsChanged(PKG, Collections.emptyList(),
+ new UserHandle(mUid));
+
+ // Verify:
+
+ // Make sure callback is unregistered
+ verify(mLauncherApps, times(1)).unregisterCallback(launcherAppsCallback.getValue());
+
+ // We're no longer a bubble
+ Notification notif2 = mService.getNotificationRecord(nr.sbn.getKey()).getNotification();
+ assertFalse(notif2.isBubbleNotification());
+ }
+
+ @Test
public void testNotificationBubbles_bubbleChildrenStay_whenGroupSummaryDismissed()
throws Exception {
// Bubbles are allowed!
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 f702d5d..0fc2bc5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -229,11 +229,12 @@
service.mStackSupervisor, mock(ActivityStartInterceptor.class));
prepareStarter(launchFlags);
final IApplicationThread caller = mock(IApplicationThread.class);
+ final WindowProcessListener listener = mock(WindowProcessListener.class);
final WindowProcessController wpc =
containsConditions(preconditions, PRECONDITION_NO_CALLER_APP)
? null : new WindowProcessController(
- service, mock(ApplicationInfo.class), null, 0, -1, null, null);
+ service, mock(ApplicationInfo.class), null, 0, -1, null, listener);
doReturn(wpc).when(service).getProcessController(anyObject());
final Intent intent = new Intent();
@@ -680,10 +681,11 @@
doReturn(realCallingUidProcState).when(mService).getUidState(realCallingUid);
// foreground activities
final IApplicationThread caller = mock(IApplicationThread.class);
+ final WindowProcessListener listener = mock(WindowProcessListener.class);
final ApplicationInfo ai = new ApplicationInfo();
ai.uid = callingUid;
final WindowProcessController callerApp =
- new WindowProcessController(mService, ai, null, callingUid, -1, null, null);
+ new WindowProcessController(mService, ai, null, callingUid, -1, null, listener);
callerApp.setHasForegroundActivities(hasForegroundActivities);
doReturn(callerApp).when(mService).getProcessController(caller);
// caller is recents
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index db4fdc77..34e487b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.Display.INVALID_DISPLAY;
import static org.junit.Assert.assertEquals;
@@ -24,7 +26,9 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
+import android.app.IApplicationThread;
import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.platform.test.annotations.Presubmit;
@@ -53,6 +57,7 @@
mMockListener = mock(WindowProcessListener.class);
mWpc = new WindowProcessController(
mService, mock(ApplicationInfo.class), null, 0, -1, null, mMockListener);
+ mWpc.setThread(mock(IApplicationThread.class));
}
@Test
@@ -132,23 +137,51 @@
@Test
public void testConfigurationForSecondaryScreen() {
- final WindowProcessController wpc = new WindowProcessController(
- mService, mock(ApplicationInfo.class), null, 0, -1, null, null);
// By default, the process should not listen to any display.
- assertEquals(INVALID_DISPLAY, wpc.getDisplayId());
+ assertEquals(INVALID_DISPLAY, mWpc.getDisplayId());
// Register to a new display as a listener.
final DisplayContent display = new TestDisplayContent.Builder(mService, 2000, 1000)
.setDensityDpi(300).setPosition(DisplayContent.POSITION_TOP).build();
- wpc.registerDisplayConfigurationListener(display);
+ mWpc.registerDisplayConfigurationListener(display);
- assertEquals(display.mDisplayId, wpc.getDisplayId());
+ assertEquals(display.mDisplayId, mWpc.getDisplayId());
final Configuration expectedConfig = mService.mRootWindowContainer.getConfiguration();
expectedConfig.updateFrom(display.getConfiguration());
- assertEquals(expectedConfig, wpc.getConfiguration());
+ assertEquals(expectedConfig, mWpc.getConfiguration());
+ }
+
+ @Test
+ public void testDelayingConfigurationChange() {
+ when(mMockListener.isCached()).thenReturn(false);
+
+ Configuration tmpConfig = new Configuration(mWpc.getConfiguration());
+ invertOrientation(tmpConfig);
+ mWpc.onConfigurationChanged(tmpConfig);
+
+ // The last reported config should be the current config as the process is not cached.
+ Configuration originalConfig = new Configuration(mWpc.getConfiguration());
+ assertEquals(mWpc.getLastReportedConfiguration(), originalConfig);
+
+ when(mMockListener.isCached()).thenReturn(true);
+ invertOrientation(tmpConfig);
+ mWpc.onConfigurationChanged(tmpConfig);
+
+ Configuration newConfig = new Configuration(mWpc.getConfiguration());
+
+ // Last reported config hasn't changed because the process is in a cached state.
+ assertEquals(mWpc.getLastReportedConfiguration(), originalConfig);
+
+ mWpc.onProcCachedStateChanged(false);
+ assertEquals(mWpc.getLastReportedConfiguration(), newConfig);
}
private TestDisplayContent createTestDisplayContentInContainer() {
return new TestDisplayContent.Builder(mService, 1000, 1500).build();
}
+
+ private static void invertOrientation(Configuration config) {
+ config.orientation = config.orientation == ORIENTATION_PORTRAIT
+ ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
+ }
}
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index d325cd8..6d2ac9d 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -115,11 +115,11 @@
public static final int BAND_ER900 = 14;
/** @hide */
- private GeranBand() {};
+ private GeranBand() {}
}
/**
- * Frenquency bands for UTRAN.
+ * Frequency bands for UTRAN.
* http://www.etsi.org/deliver/etsi_ts/125100_125199/125104/13.03.00_60/ts_125104v130p.pdf
*/
public static final class UtranBand {
@@ -146,12 +146,19 @@
public static final int BAND_25 = 25;
public static final int BAND_26 = 26;
+ /** Frequency bands for TD-SCDMA. Defined in 3GPP TS 25.102, Table 5.2. */
+ public static final int BAND_A = 101;
+ public static final int BAND_B = 102;
+ public static final int BAND_C = 103;
+ public static final int BAND_D = 104;
+ public static final int BAND_E = 105;
+ public static final int BAND_F = 106;
/** @hide */
- private UtranBand() {};
+ private UtranBand() {}
}
/**
- * Frenquency bands for EUTRAN.
+ * Frequency bands for EUTRAN.
* http://www.etsi.org/deliver/etsi_ts/136100_136199/136101/14.03.00_60/ts_136101v140p.pdf
*/
public static final class EutranBand {
@@ -209,7 +216,7 @@
}
/**
- * Frenquency bands for CDMA2000.
+ * Frequency bands for CDMA2000.
* http://www.3gpp2.org/Public_html/Specs/C.S0057-E_v1.0_Bandclass_Specification.pdf
* @hide
*
@@ -240,7 +247,7 @@
public static final int BAND_21 = 22;
/** @hide */
- private CdmaBands() {};
+ private CdmaBands() {}
}
/**
@@ -295,7 +302,7 @@
public static final int BAND_261 = 261;
/** @hide */
- private NgranBands() {};
+ private NgranBands() {}
}
/** @hide */
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index ff31d3e..7abad72 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -17,6 +17,7 @@
package android.telephony;
import android.Manifest;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -27,6 +28,7 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
+import android.net.ipsec.ike.SaProposal;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.service.carrier.CarrierService;
@@ -3417,6 +3419,369 @@
public static final String KEY_PREVENT_CLIR_ACTIVATION_AND_DEACTIVATION_CODE_BOOL =
"prevent_clir_activation_and_deactivation_code_bool";
+ /**
+ * Configs used for epdg tunnel bring up.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc7296">RFC 7296, Internet Key Exchange
+ * Protocol Version 2 (IKEv2)</a>
+ */
+ public static final class Iwlan {
+ /** Prefix of all Epdg.KEY_* constants. */
+ public static final String KEY_PREFIX = "iwlan.";
+
+ /**
+ * Time in seconds after which the child security association session is terminated if
+ * rekey procedure is not successful. If not set or set to <= 0, the default value is
+ * 3600 seconds.
+ */
+ public static final String KEY_CHILD_SA_REKEY_HARD_TIMER_SEC_INT =
+ KEY_PREFIX + "child_sa_rekey_hard_timer_sec_int";
+
+ /**
+ * Time in seconds after which the child session rekey procedure is started. If not set or
+ * set to <= 0, default value is 3000 seconds.
+ */
+ public static final String KEY_CHILD_SA_REKEY_SOFT_TIMER_SEC_INT =
+ KEY_PREFIX + "child_sa_rekey_soft_timer_sec_int";
+
+ /** Supported DH groups for IKE negotiation.
+ * Possible values are {@link #DH_GROUP_NONE}, {@link #DH_GROUP_1024_BIT_MODP},
+ * {@link #DH_GROUP_2048_BIT_MODP}
+ */
+ public static final String KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY =
+ KEY_PREFIX + "diffie_hellman_groups_int_array";
+
+ /**
+ * Time in seconds after which a dead peer detection (DPD) request is sent.
+ * If not set or set to <= 0, default value is 120 seconds.
+ */
+ public static final String KEY_DPD_TIMER_SEC_INT = KEY_PREFIX + "dpd_timer_sec_int";
+
+ /**
+ * Method used to authenticate epdg server.
+ * Possible values are {@link #AUTHENTICATION_METHOD_EAP_ONLY},
+ * {@link #AUTHENTICATION_METHOD_CERT}
+ */
+ public static final String KEY_EPDG_AUTHENTICATION_METHOD_INT =
+ KEY_PREFIX + "epdg_authentication_method_int";
+
+ /**
+ * A priority list of ePDG addresses to be used.
+ * Possible values are {@link #EPDG_ADDRESS_STATIC}, {@link #EPDG_ADDRESS_PLMN},
+ * {@link #EPDG_ADDRESS_PCO}
+ */
+ public static final String KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY =
+ KEY_PREFIX + "epdg_address_priority_int_array";
+
+ /** Epdg static IP address or FQDN */
+ public static final String KEY_EPDG_STATIC_ADDRESS_STRING =
+ KEY_PREFIX + "epdg_static_address_string";
+
+ /** Epdg static IP address or FQDN for roaming */
+ public static final String KEY_EPDG_STATIC_ADDRESS_ROAMING_STRING =
+ KEY_PREFIX + "epdg_static_address_roaming_string";
+
+ /**
+ * List of supported key sizes for AES Cipher Block Chaining (CBC) encryption mode of child
+ * session.
+ * Possible values are {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128},
+ * {@link #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256}
+ */
+ public static final String KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY =
+ KEY_PREFIX + "child_session_aes_cbc_key_size_int_array";
+
+ /**
+ * List of supported key sizes for AES counter (CTR) encryption mode of child session.
+ * Possible values are {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128},
+ * {@link #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256}
+ */
+ public static final String KEY_CHILD_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY =
+ KEY_PREFIX + "child_encryption_aes_ctr_key_size_int_array";
+
+ /**
+ * List of supported encryption algorithms for child session.
+ * Possible values are {@link #ENCRYPTION_ALGORITHM_3DES},
+ * {@link #ENCRYPTION_ALGORITHM_AES_CBC}, {@link #ENCRYPTION_ALGORITHM_AES_GCM_8},
+ * {@link #ENCRYPTION_ALGORITHM_AES_GCM_12}, {@link #ENCRYPTION_ALGORITHM_AES_GCM_16}
+ */
+ public static final String KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY =
+ KEY_PREFIX + "supported_child_session_encryption_algorithms_int_array";
+
+ /** Controls if IKE message fragmentation is enabled. */
+ public static final String KEY_IKE_FRAGMENTATION_ENABLED_BOOL =
+ KEY_PREFIX + "ike_fragmentation_enabled_bool";
+
+ /**
+ * Time in seconds after which the IKE session is terminated if rekey procedure is not
+ * successful. If not set or set to <= 0, default value is 3600 seconds.
+ */
+ public static final String KEY_IKE_REKEY_HARD_TIMER_SEC_INT =
+ KEY_PREFIX + "ike_rekey_hard_timer_in_sec";
+
+ /**
+ * Time in seconds after which the IKE session rekey procedure is started. If not set or
+ * set to <= 0, default value is 3000 seconds.
+ */
+ public static final String KEY_IKE_REKEY_SOFT_TIMER_SEC_INT =
+ KEY_PREFIX + "ike_rekey_soft_timer_sec_int";
+
+ /**
+ * List of supported key sizes for AES Cipher Block Chaining (CBC) encryption mode of IKE
+ * session.
+ * Possible values - {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128},
+ * {@link #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256}
+ */
+ public static final String KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY =
+ KEY_PREFIX + "ike_session_encryption_aes_cbc_key_size_int_array";
+
+ /**
+ * List of supported key sizes for AES counter (CTR) encryption mode of IKE session.
+ * Possible values - {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128},
+ * {@link #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256}
+ */
+ public static final String KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY =
+ KEY_PREFIX + "ike_session_aes_ctr_key_size_int_array";
+
+ /**
+ * List of supported encryption algorithms for IKE session.
+ * Possible values are {@link #ENCRYPTION_ALGORITHM_3DES},
+ * {@link #ENCRYPTION_ALGORITHM_AES_CBC}, {@link #ENCRYPTION_ALGORITHM_AES_GCM_8},
+ * {@link #ENCRYPTION_ALGORITHM_AES_GCM_12}, {@link #ENCRYPTION_ALGORITHM_AES_GCM_16}
+ */
+ public static final String KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY =
+ KEY_PREFIX + "supported_ike_session_encryption_algorithms_int_array";
+
+ /**
+ * List of supported integrity algorithms for IKE session
+ * Possible values are {@link #INTEGRITY_ALGORITHM_NONE},
+ * {@link #INTEGRITY_ALGORITHM_HMAC_SHA1_96}, {@link #INTEGRITY_ALGORITHM_AES_XCBC_96},
+ * {@link #INTEGRITY_ALGORITHM_HMAC_SHA2_256_128},
+ * {@link #INTEGRITY_ALGORITHM_HMAC_SHA2_384_192},
+ * {@link #INTEGRITY_ALGORITHM_HMAC_SHA2_512_256}
+ */
+ public static final String KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY =
+ KEY_PREFIX + "supported_integrity_algorithms_int_array";
+
+ /** Maximum number of retries for tunnel establishment. */
+ public static final String KEY_MAX_RETRIES_INT = KEY_PREFIX + "max_retries_int";
+
+ /** Controls if nat traversal should be enabled. */
+ public static final String KEY_NATT_ENABLED_BOOL = KEY_PREFIX + "natt_enabled_bool";
+
+ /**
+ * Time in seconds after which a NATT keep alive message is sent. If not set or set to <= 0,
+ * default value is 20 seconds.
+ */
+ public static final String KEY_NATT_KEEP_ALIVE_TIMER_SEC_INT =
+ KEY_PREFIX + "natt_keep_alive_timer_sec_int";
+
+ /** List of comma separated MCC/MNCs used to create ePDG FQDN as per 3GPP TS 23.003 */
+ public static final String KEY_MCC_MNCS_STRING_ARRAY = KEY_PREFIX + "mcc_mncs_string_array";
+
+ /**
+ * List of supported pseudo random function algorithms for IKE session
+ * Possible values are {@link #PSEUDORANDOM_FUNCTION_HMAC_SHA1},
+ * {@link #PSEUDORANDOM_FUNCTION_AES128_XCBC}
+ */
+ public static final String KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY = KEY_PREFIX +
+ "supported_prf_algorithms_int_array";
+
+ /**
+ * Time in seconds after which IKE message is retransmitted. If not set or set to <= 0,
+ * default value is 2 seconds.
+ */
+ public static final String KEY_RETRANSMIT_TIMER_SEC_INT =
+ KEY_PREFIX + "retransmit_timer_sec_int";
+
+ /** @hide */
+ @IntDef({
+ AUTHENTICATION_METHOD_EAP_ONLY,
+ AUTHENTICATION_METHOD_CERT
+ })
+ public @interface AuthenticationMethodType {}
+
+ /**
+ * Certificate sent from the server is ignored. Only Extensible Authentication Protocol
+ * (EAP) is used to authenticate the server.
+ * EAP_ONLY_AUTH payload is added to IKE_AUTH request if supported.
+ * @see <a href="https://tools.ietf.org/html/rfc5998">RFC 5998</a>
+ */
+ public static final int AUTHENTICATION_METHOD_EAP_ONLY = 0;
+ /** Server is authenticated using its certificate. */
+ public static final int AUTHENTICATION_METHOD_CERT = 1;
+
+ /** @hide */
+ @IntDef({
+ EPDG_ADDRESS_STATIC,
+ EPDG_ADDRESS_PLMN,
+ EPDG_ADDRESS_PCO
+ })
+ public @interface EpdgAddressType {}
+
+ /** Use static epdg address. */
+ public static final int EPDG_ADDRESS_STATIC = 0;
+ /** Construct the epdg address using plmn. */
+ public static final int EPDG_ADDRESS_PLMN = 1;
+ /**
+ * Use the epdg address received in protocol configuration options (PCO) from the
+ * network.
+ */
+ public static final int EPDG_ADDRESS_PCO = 2;
+
+ /** @hide */
+ @IntDef({
+ KEY_LEN_UNUSED,
+ KEY_LEN_AES_128,
+ KEY_LEN_AES_192,
+ KEY_LEN_AES_256
+ })
+ public @interface EncrpytionKeyLengthType {}
+
+ public static final int KEY_LEN_UNUSED = SaProposal.KEY_LEN_UNUSED;
+ /** AES Encryption/Ciphering Algorithm key length 128 bits. */
+ public static final int KEY_LEN_AES_128 = SaProposal.KEY_LEN_AES_128;
+ /** AES Encryption/Ciphering Algorithm key length 192 bits. */
+ public static final int KEY_LEN_AES_192 = SaProposal.KEY_LEN_AES_192;
+ /** AES Encryption/Ciphering Algorithm key length 256 bits. */
+ public static final int KEY_LEN_AES_256 = SaProposal.KEY_LEN_AES_256;
+
+ /** @hide */
+ @IntDef({
+ DH_GROUP_NONE,
+ DH_GROUP_1024_BIT_MODP,
+ DH_GROUP_2048_BIT_MODP
+ })
+ public @interface DhGroup {}
+
+ /** None Diffie-Hellman Group. */
+ public static final int DH_GROUP_NONE = SaProposal.DH_GROUP_NONE;
+ /** 1024-bit MODP Diffie-Hellman Group. */
+ public static final int DH_GROUP_1024_BIT_MODP = SaProposal.DH_GROUP_1024_BIT_MODP;
+ /** 2048-bit MODP Diffie-Hellman Group. */
+ public static final int DH_GROUP_2048_BIT_MODP = SaProposal.DH_GROUP_2048_BIT_MODP;
+
+ /** @hide */
+ @IntDef({
+ ENCRYPTION_ALGORITHM_3DES,
+ ENCRYPTION_ALGORITHM_AES_CBC,
+ ENCRYPTION_ALGORITHM_AES_GCM_8,
+ ENCRYPTION_ALGORITHM_AES_GCM_12,
+ ENCRYPTION_ALGORITHM_AES_GCM_16
+ })
+ public @interface EncryptionAlgorithm {}
+
+ /** 3DES Encryption/Ciphering Algorithm. */
+ public static final int ENCRYPTION_ALGORITHM_3DES = SaProposal.ENCRYPTION_ALGORITHM_3DES;
+ /** AES-CBC Encryption/Ciphering Algorithm. */
+ public static final int ENCRYPTION_ALGORITHM_AES_CBC =
+ SaProposal.ENCRYPTION_ALGORITHM_AES_CBC;
+
+ /**
+ * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm with 8-octet ICV
+ * (truncation).
+ */
+ public static final int ENCRYPTION_ALGORITHM_AES_GCM_8 =
+ SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8;
+ /**
+ * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm with 12-octet ICV
+ * (truncation).
+ */
+ public static final int ENCRYPTION_ALGORITHM_AES_GCM_12 =
+ SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12;
+ /**
+ * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm with 16-octet ICV
+ * (truncation).
+ */
+ public static final int ENCRYPTION_ALGORITHM_AES_GCM_16 =
+ SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16;
+
+ /** @hide */
+ @IntDef({
+ INTEGRITY_ALGORITHM_NONE,
+ INTEGRITY_ALGORITHM_HMAC_SHA1_96,
+ INTEGRITY_ALGORITHM_AES_XCBC_96,
+ INTEGRITY_ALGORITHM_HMAC_SHA2_256_128,
+ INTEGRITY_ALGORITHM_HMAC_SHA2_384_192,
+ INTEGRITY_ALGORITHM_HMAC_SHA2_512_256
+ })
+ public @interface IntegrityAlgorithm {}
+
+ /** None Authentication/Integrity Algorithm. */
+ public static final int INTEGRITY_ALGORITHM_NONE = SaProposal.INTEGRITY_ALGORITHM_NONE;
+ /** HMAC-SHA1 Authentication/Integrity Algorithm. */
+ public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 =
+ SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96;
+ /** AES-XCBC-96 Authentication/Integrity Algorithm. */
+ public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 =
+ SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96;
+ /** HMAC-SHA256 Authentication/Integrity Algorithm with 128-bit truncation. */
+ public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 =
+ SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128;
+ /** HMAC-SHA384 Authentication/Integrity Algorithm with 192-bit truncation. */
+ public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 =
+ SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192;
+ /** HMAC-SHA512 Authentication/Integrity Algorithm with 256-bit truncation. */
+ public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 =
+ SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256;
+
+ /** @hide */
+ @IntDef({
+ PSEUDORANDOM_FUNCTION_HMAC_SHA1,
+ PSEUDORANDOM_FUNCTION_AES128_XCBC
+ })
+ public @interface PseudorandomFunction {}
+
+ /** HMAC-SHA1 Pseudorandom Function. */
+ public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 =
+ SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1;
+ /** AES128-XCBC Pseudorandom Function. */
+ public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC =
+ SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC;
+
+ private Iwlan() {}
+
+ private static PersistableBundle getDefaults() {
+ PersistableBundle defaults = new PersistableBundle();
+ defaults.putInt(KEY_IKE_REKEY_SOFT_TIMER_SEC_INT, 3000);
+ defaults.putInt(KEY_IKE_REKEY_HARD_TIMER_SEC_INT, 3600);
+ defaults.putInt(KEY_CHILD_SA_REKEY_SOFT_TIMER_SEC_INT, 3000);
+ defaults.putInt(KEY_CHILD_SA_REKEY_HARD_TIMER_SEC_INT, 3600);
+ defaults.putInt(KEY_RETRANSMIT_TIMER_SEC_INT, 2);
+ defaults.putInt(KEY_DPD_TIMER_SEC_INT, 120);
+ defaults.putInt(KEY_MAX_RETRIES_INT, 3);
+ defaults.putIntArray(KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY,
+ new int[]{DH_GROUP_1024_BIT_MODP, DH_GROUP_2048_BIT_MODP});
+ defaults.putIntArray(KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY,
+ new int[]{ENCRYPTION_ALGORITHM_3DES, ENCRYPTION_ALGORITHM_AES_CBC});
+ defaults.putIntArray(KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY,
+ new int[]{ENCRYPTION_ALGORITHM_3DES, ENCRYPTION_ALGORITHM_AES_CBC});
+ defaults.putIntArray(KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY,
+ new int[]{INTEGRITY_ALGORITHM_AES_XCBC_96, INTEGRITY_ALGORITHM_HMAC_SHA1_96,
+ INTEGRITY_ALGORITHM_HMAC_SHA2_256_128});
+ defaults.putIntArray(KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY,
+ new int[]{PSEUDORANDOM_FUNCTION_HMAC_SHA1, PSEUDORANDOM_FUNCTION_AES128_XCBC});
+ defaults.putBoolean(KEY_NATT_ENABLED_BOOL, true);
+ defaults.putInt(KEY_EPDG_AUTHENTICATION_METHOD_INT, AUTHENTICATION_METHOD_CERT);
+ defaults.putString(KEY_EPDG_STATIC_ADDRESS_STRING, "");
+ defaults.putString(KEY_EPDG_STATIC_ADDRESS_ROAMING_STRING, "");
+ defaults.putInt(KEY_NATT_KEEP_ALIVE_TIMER_SEC_INT, 20);
+ defaults.putIntArray(KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY,
+ new int[]{KEY_LEN_AES_128, KEY_LEN_AES_256});
+ defaults.putIntArray(KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY,
+ new int[]{KEY_LEN_AES_128});
+ defaults.putIntArray(KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY,
+ new int[]{KEY_LEN_AES_128, KEY_LEN_AES_256});
+ defaults.putIntArray(KEY_CHILD_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY,
+ new int[]{KEY_LEN_AES_128});
+ defaults.putBoolean(KEY_IKE_FRAGMENTATION_ENABLED_BOOL, false);
+ defaults.putIntArray(KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY, new int[]{EPDG_ADDRESS_PLMN,
+ EPDG_ADDRESS_STATIC});
+ defaults.putStringArray(KEY_MCC_MNCS_STRING_ARRAY, new String[]{});
+
+ return defaults;
+ }
+ }
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -3908,6 +4273,7 @@
// Default wifi configurations.
sDefaults.putAll(Wifi.getDefaults());
sDefaults.putBoolean(ENABLE_EAP_METHOD_PREFIX_BOOL, false);
+ sDefaults.putAll(Iwlan.getDefaults());
}
/**
diff --git a/telephony/java/android/telephony/CdmaEriInformation.java b/telephony/java/android/telephony/CdmaEriInformation.java
new file mode 100644
index 0000000..1cd9d30
--- /dev/null
+++ b/telephony/java/android/telephony/CdmaEriInformation.java
@@ -0,0 +1,170 @@
+/**
+ * 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;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * CDMA ERI (Enhanced Roaming Indicator) information.
+ *
+ * This contains the following ERI information
+ *
+ * 1. ERI (Enhanced Roaming Indicator) icon index. The number is assigned by
+ * 3GPP2 C.R1001-H v1.0 Table 8.1-1. Additionally carriers define their own
+ * ERI icon index.
+ * 2. CDMA ERI icon mode. This represents how the icon should be displayed.
+ * Its one of the following CDMA ERI icon mode
+ * {@link android.telephony.CdmaEriInformation#ERI_ICON_MODE_NORMAL}
+ * {@link android.telephony.CdmaEriInformation#ERI_ICON_MODE_FLASH}
+ *
+ * @hide
+ */
+@SystemApi
+public final class CdmaEriInformation implements Parcelable {
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"ERI_"}, value = {
+ ERI_ON,
+ ERI_OFF,
+ ERI_FLASH
+ })
+ public @interface EriIconIndex {}
+
+ /**
+ * ERI (Enhanced Roaming Indicator) is ON i.e value 0 defined by
+ * 3GPP2 C.R1001-H v1.0 Table 8.1-1.
+ */
+ public static final int ERI_ON = 0;
+
+ /**
+ * ERI (Enhanced Roaming Indicator) is OFF i.e value 1 defined by
+ * 3GPP2 C.R1001-H v1.0 Table 8.1-1.
+ */
+ public static final int ERI_OFF = 1;
+
+ /**
+ * ERI (Enhanced Roaming Indicator) is FLASH i.e value 2 defined by
+ * 3GPP2 C.R1001-H v1.0 Table 8.1-1.
+ */
+ public static final int ERI_FLASH = 2;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"ERI_ICON_MODE_"}, value = {
+ ERI_ICON_MODE_NORMAL,
+ ERI_ICON_MODE_FLASH
+ })
+ public @interface EriIconMode {}
+
+ /**
+ * ERI (Enhanced Roaming Indicator) icon mode is normal. This constant represents that
+ * the ERI icon should be displayed normally.
+ *
+ * Note: ERI is defined 3GPP2 C.R1001-H Table 8.1-1
+ */
+ public static final int ERI_ICON_MODE_NORMAL = 0;
+
+ /**
+ * ERI (Enhanced Roaming Indicator) icon mode flash. This constant represents that
+ * the ERI icon should be flashing.
+ *
+ * Note: ERI is defined 3GPP2 C.R1001-H Table 8.1-1
+ */
+ public static final int ERI_ICON_MODE_FLASH = 1;
+
+ private @EriIconIndex int mIconIndex;
+ private @EriIconMode int mIconMode;
+
+ /**
+ * Creates CdmaEriInformation from iconIndex and iconMode
+ *
+ * @hide
+ */
+ public CdmaEriInformation(@EriIconIndex int iconIndex, @EriIconMode int iconMode) {
+ mIconIndex = iconIndex;
+ mIconMode = iconMode;
+ }
+
+ /** Gets the ERI icon index */
+ public @EriIconIndex int getEriIconIndex() {
+ return mIconIndex;
+ }
+
+ /**
+ * Sets the ERI icon index
+ *
+ * @hide
+ */
+ public void setEriIconIndex(@EriIconIndex int iconIndex) {
+ mIconIndex = iconIndex;
+ }
+
+ /** Gets the ERI icon mode */
+ public @EriIconMode int getEriIconMode() {
+ return mIconMode;
+ }
+
+ /**
+ * Sets the ERI icon mode
+ *
+ * @hide
+ */
+ public void setEriIconMode(@EriIconMode int iconMode) {
+ mIconMode = iconMode;
+ }
+ /** Implement the Parcelable interface */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mIconIndex);
+ dest.writeInt(mIconMode);
+ }
+
+ /** Implement the Parcelable interface */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Construct a CdmaEriInformation object from the given parcel
+ */
+ private CdmaEriInformation(Parcel in) {
+ mIconIndex = in.readInt();
+ mIconMode = in.readInt();
+ }
+
+ /** Implement the Parcelable interface */
+ public static final @android.annotation.NonNull Parcelable.Creator<CdmaEriInformation> CREATOR =
+ new Parcelable.Creator<CdmaEriInformation>() {
+ @Override
+ public CdmaEriInformation createFromParcel(Parcel in) {
+ return new CdmaEriInformation(in);
+ }
+
+ @Override
+ public CdmaEriInformation[] newArray(int size) {
+ return new CdmaEriInformation[size];
+ }
+ };
+}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a839426..1c622f9 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1365,6 +1365,7 @@
*
* @hide
*/
+ @SystemApi
public static final String EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE =
"android.telephony.extra.DEFAULT_SUBSCRIPTION_SELECT_TYPE";
@@ -1384,6 +1385,7 @@
* to indicate there's no need to re-select any default subscription.
* @hide
*/
+ @SystemApi
public static final int EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE = 0;
/**
@@ -1391,6 +1393,7 @@
* to indicate there's a need to select default data subscription.
* @hide
*/
+ @SystemApi
public static final int EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DATA = 1;
/**
@@ -1398,6 +1401,7 @@
* to indicate there's a need to select default voice call subscription.
* @hide
*/
+ @SystemApi
public static final int EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_VOICE = 2;
/**
@@ -1405,6 +1409,7 @@
* to indicate there's a need to select default sms subscription.
* @hide
*/
+ @SystemApi
public static final int EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_SMS = 3;
/**
@@ -1414,6 +1419,7 @@
* which subscription should be the default subscription.
* @hide
*/
+ @SystemApi
public static final int EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_ALL = 4;
/**
@@ -1423,6 +1429,7 @@
*
* @hide
*/
+ @SystemApi
public static final String EXTRA_SIM_COMBINATION_WARNING_TYPE =
"android.telephony.extra.SIM_COMBINATION_WARNING_TYPE";
@@ -1439,6 +1446,7 @@
* to indicate there's no SIM combination warning.
* @hide
*/
+ @SystemApi
public static final int EXTRA_SIM_COMBINATION_WARNING_TYPE_NONE = 0;
/**
@@ -1446,6 +1454,7 @@
* to indicate two active SIMs are both CDMA hence there might be functional limitation.
* @hide
*/
+ @SystemApi
public static final int EXTRA_SIM_COMBINATION_WARNING_TYPE_DUAL_CDMA = 1;
/**
@@ -1456,6 +1465,7 @@
*
* @hide
*/
+ @SystemApi
public static final String EXTRA_SIM_COMBINATION_NAMES =
"android.telephony.extra.SIM_COMBINATION_NAMES";
@@ -5614,19 +5624,25 @@
}
/**
- * Returns the CDMA ERI icon index to display
+ * Get the CDMA ERI (Enhanced Roaming Indicator) information
+ *
+ * Returns {@link android.telephony#CdmaEriInformation}
+ *
* @hide
*/
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public int getCdmaEriIconIndex() {
- return getCdmaEriIconIndex(getSubId());
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @SystemApi
+ @NonNull
+ public CdmaEriInformation getCdmaEriInformation() {
+ return new CdmaEriInformation(
+ getCdmaEriIconMode(getSubId()), getCdmaEriIconIndex(getSubId()));
}
/**
* Returns the CDMA ERI icon index to display for a subscription
* @hide
*/
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@UnsupportedAppUsage
public int getCdmaEriIconIndex(int subId) {
try {
@@ -5644,25 +5660,13 @@
}
/**
- * Returns the CDMA ERI icon mode,
- * 0 - ON
- * 1 - FLASHING
- *
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public int getCdmaEriIconMode() {
- return getCdmaEriIconMode(getSubId());
- }
-
- /**
* Returns the CDMA ERI icon mode for a subscription.
* 0 - ON
* 1 - FLASHING
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@UnsupportedAppUsage
public int getCdmaEriIconMode(int subId) {
try {
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 3f260eb..8c9765b 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -302,15 +302,30 @@
* updateImsCallRatFromExtras(Bundle)} to determine whether to set the
* {@link android.telecom.TelecomManager#EXTRA_CALL_NETWORK_TYPE} extra value and
* {@link android.telecom.Connection#PROPERTY_WIFI} property on a connection.
+ * @deprecated the constants associated with this extra are hidden, instead use
+ * {@link #EXTRA_CALL_NETWORK_TYPE}.
*/
+ @Deprecated
public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
/**
+ * Extra key with an {@code int} value which can be set in {@link #setCallExtraInt(String, int)}
+ * to indicate the network type used for a call.
+ * <p>
+ * Valid values are defined by {@code TelephonyManager.NETWORK_TYPE_*} constants. An example may
+ * be {@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE}.
+ */
+ public static final String EXTRA_CALL_NETWORK_TYPE =
+ "android.telephony.ims.extra.CALL_NETWORK_TYPE";
+
+ /**
* Similar to {@link #EXTRA_CALL_RAT_TYPE}, except with a lowercase 'c'. Used to ensure
* compatibility with modems that are non-compliant with the {@link #EXTRA_CALL_RAT_TYPE}
* extra key. Should be removed when the non-compliant modems are fixed.
* @hide
+ * @deprecated Use {@link #EXTRA_CALL_NETWORK_TYPE} instead.
*/
+ @Deprecated
public static final String EXTRA_CALL_RAT_TYPE_ALT = "callRadioTech";
/** @hide */
diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java
index 5adc99e..1b583fd 100644
--- a/telephony/java/android/telephony/ims/ImsCallSession.java
+++ b/telephony/java/android/telephony/ims/ImsCallSession.java
@@ -25,8 +25,6 @@
import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsVideoCallProvider;
-import java.util.Objects;
-
/**
* Provides the call initiation/termination, and media exchange between two IMS endpoints.
* It directly communicates with IMS service which implements the IMS protocol behavior.
@@ -346,7 +344,7 @@
}
/**
- * Called when an {@link ImsCallSession} may handover from one radio technology to another.
+ * Called when an {@link ImsCallSession} may handover from one network type to another.
* For example, the session may handover from WIFI to LTE if conditions are right.
* <p>
* If handover is attempted,
@@ -355,24 +353,24 @@
* called to indicate the success or failure of the handover.
*
* @param session IMS session object
- * @param srcAccessTech original access technology
- * @param targetAccessTech new access technology
+ * @param srcNetworkType original network type
+ * @param targetNetworkType new network type
*/
- public void callSessionMayHandover(ImsCallSession session, int srcAccessTech,
- int targetAccessTech) {
+ public void callSessionMayHandover(ImsCallSession session, int srcNetworkType,
+ int targetNetworkType) {
// no-op
}
/**
- * Called when session access technology changes
+ * Called when session network type changes
*
* @param session IMS session object
- * @param srcAccessTech original access technology
- * @param targetAccessTech new access technology
+ * @param srcNetworkType original network type
+ * @param targetNetworkType new network type
* @param reasonInfo
*/
public void callSessionHandover(ImsCallSession session,
- int srcAccessTech, int targetAccessTech,
+ int srcNetworkType, int targetNetworkType,
ImsReasonInfo reasonInfo) {
// no-op
}
@@ -381,12 +379,12 @@
* Called when session access technology change fails
*
* @param session IMS session object
- * @param srcAccessTech original access technology
- * @param targetAccessTech new access technology
+ * @param srcNetworkType original access technology
+ * @param targetNetworkType new access technology
* @param reasonInfo handover failure reason
*/
public void callSessionHandoverFailed(ImsCallSession session,
- int srcAccessTech, int targetAccessTech,
+ int srcNetworkType, int targetNetworkType,
ImsReasonInfo reasonInfo) {
// no-op
}
@@ -1303,20 +1301,19 @@
/**
* Notifies of a case where a {@link ImsCallSession} may
* potentially handover from one radio technology to another.
- * @param srcAccessTech The source radio access technology; one of the access technology
- * constants defined in {@link android.telephony.ServiceState}. For
- * example
- * {@link android.telephony.ServiceState#RIL_RADIO_TECHNOLOGY_LTE}.
- * @param targetAccessTech The target radio access technology; one of the access technology
- * constants defined in {@link android.telephony.ServiceState}. For
- * example
- * {@link android.telephony.ServiceState#RIL_RADIO_TECHNOLOGY_LTE}.
+ * @param srcNetworkType The source network type; one of the network type constants defined
+ * in {@link android.telephony.TelephonyManager}. For example
+ * {@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE}.
+ * @param targetNetworkType The target radio access technology; one of the network type
+ * constants defined in {@link android.telephony.TelephonyManager}.
+ * For example
+ * {@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE}.
*/
@Override
- public void callSessionMayHandover(int srcAccessTech, int targetAccessTech) {
+ public void callSessionMayHandover(int srcNetworkType, int targetNetworkType) {
if (mListener != null) {
- mListener.callSessionMayHandover(ImsCallSession.this, srcAccessTech,
- targetAccessTech);
+ mListener.callSessionMayHandover(ImsCallSession.this, srcNetworkType,
+ targetNetworkType);
}
}
@@ -1324,11 +1321,11 @@
* Notifies of handover information for this call
*/
@Override
- public void callSessionHandover(int srcAccessTech, int targetAccessTech,
+ public void callSessionHandover(int srcNetworkType, int targetNetworkType,
ImsReasonInfo reasonInfo) {
if (mListener != null) {
- mListener.callSessionHandover(ImsCallSession.this, srcAccessTech,
- targetAccessTech, reasonInfo);
+ mListener.callSessionHandover(ImsCallSession.this, srcNetworkType,
+ targetNetworkType, reasonInfo);
}
}
@@ -1336,11 +1333,11 @@
* Notifies of handover failure info for this call
*/
@Override
- public void callSessionHandoverFailed(int srcAccessTech, int targetAccessTech,
+ public void callSessionHandoverFailed(int srcNetworkType, int targetNetworkType,
ImsReasonInfo reasonInfo) {
if (mListener != null) {
- mListener.callSessionHandoverFailed(ImsCallSession.this, srcAccessTech,
- targetAccessTech, reasonInfo);
+ mListener.callSessionHandoverFailed(ImsCallSession.this, srcNetworkType,
+ targetNetworkType, reasonInfo);
}
}
diff --git a/telephony/java/android/telephony/ims/ImsCallSessionListener.java b/telephony/java/android/telephony/ims/ImsCallSessionListener.java
index e11886f..025721c 100644
--- a/telephony/java/android/telephony/ims/ImsCallSessionListener.java
+++ b/telephony/java/android/telephony/ims/ImsCallSessionListener.java
@@ -17,10 +17,13 @@
package android.telephony.ims;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.os.RemoteException;
+import android.telephony.Annotation;
import android.telephony.CallQuality;
+import android.telephony.ServiceState;
import android.telephony.ims.aidl.IImsCallSessionListener;
import android.telephony.ims.stub.ImsCallSessionImplBase;
@@ -476,11 +479,27 @@
* @param targetAccessTech The target radio access technology; one of the access technology
* constants defined in {@link android.telephony.ServiceState}. For example
* {@link android.telephony.ServiceState#RIL_RADIO_TECHNOLOGY_LTE}.
+ * @deprecated Uses hidden constants for radio access technology, use
+ * {@link #onMayHandover(int, int)} instead.
*/
- public void callSessionMayHandover(int srcAccessTech, int targetAccessTech)
- {
+ @Deprecated
+ public void callSessionMayHandover(int srcAccessTech, int targetAccessTech) {
+ // Use new API internally.
+ onMayHandover(ServiceState.rilRadioTechnologyToNetworkType(srcAccessTech),
+ ServiceState.rilRadioTechnologyToNetworkType(targetAccessTech));
+ }
+
+ /**
+ * Notify the framework that the associated {@link ImsCallSession} may handover from one network
+ * type to another.
+ *
+ * @param srcNetworkType The source network type.
+ * @param targetNetworkType The target network type.
+ */
+ public void onMayHandover(@Annotation.NetworkType int srcNetworkType,
+ @Annotation.NetworkType int targetNetworkType) {
try {
- mListener.callSessionMayHandover(srcAccessTech, targetAccessTech);
+ mListener.callSessionMayHandover(srcNetworkType, targetNetworkType);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -494,11 +513,29 @@
* @param targetAccessTech new access technology, defined in
* {@link android.telephony.ServiceState}.
* @param reasonInfo The {@link ImsReasonInfo} associated with this handover.
+ * @deprecated Uses hidden radio access technology constants, use
+ * {@link #onHandover(int, int, ImsReasonInfo)} instead.
*/
+ @Deprecated
public void callSessionHandover(int srcAccessTech, int targetAccessTech,
ImsReasonInfo reasonInfo) {
+ // Use new API internally.
+ onHandover(ServiceState.rilRadioTechnologyToNetworkType(srcAccessTech),
+ ServiceState.rilRadioTechnologyToNetworkType(targetAccessTech), reasonInfo);
+ }
+
+ /**
+ * Notify the framework that the associated {@link ImsCallSession} has handed over from one
+ * network type to another.
+ *
+ * @param srcNetworkType original network type.
+ * @param targetNetworkType target network type after handover..
+ * @param reasonInfo An optional {@link ImsReasonInfo} associated with this handover.
+ */
+ public void onHandover(@Annotation.NetworkType int srcNetworkType,
+ @Annotation.NetworkType int targetNetworkType, @Nullable ImsReasonInfo reasonInfo) {
try {
- mListener.callSessionHandover(srcAccessTech, targetAccessTech, reasonInfo);
+ mListener.callSessionHandover(srcNetworkType, targetNetworkType, reasonInfo);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -510,11 +547,28 @@
* @param srcAccessTech original access technology
* @param targetAccessTech new access technology
* @param reasonInfo An {@link ImsReasonInfo} detailing the reason for the failure.
+ * @deprecated Uses hidden radio access technology constants, use
+ * {@link #onHandoverFailed(int, int, ImsReasonInfo)} instead
*/
+ @Deprecated
public void callSessionHandoverFailed(int srcAccessTech, int targetAccessTech,
ImsReasonInfo reasonInfo) {
+ // Use new API internally.
+ onHandoverFailed(ServiceState.rilRadioTechnologyToNetworkType(srcAccessTech),
+ ServiceState.rilRadioTechnologyToNetworkType(targetAccessTech), reasonInfo);
+ }
+
+ /**
+ * The IMS call session's access technology change has failed..
+ *
+ * @param srcNetworkType original network type.
+ * @param targetNetworkType target network type that the handover failed for.
+ * @param reasonInfo An {@link ImsReasonInfo} detailing the reason for the failure.
+ */
+ public void onHandoverFailed(@Annotation.NetworkType int srcNetworkType,
+ @Annotation.NetworkType int targetNetworkType, @NonNull ImsReasonInfo reasonInfo) {
try {
- mListener.callSessionHandoverFailed(srcAccessTech, targetAccessTech, reasonInfo);
+ mListener.callSessionHandoverFailed(srcNetworkType, targetNetworkType, reasonInfo);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
diff --git a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
index d64e67a..cc2ebb9 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
@@ -92,11 +92,11 @@
/**
* Notifies of handover information for this call
*/
- void callSessionHandover(int srcAccessTech, int targetAccessTech,
+ void callSessionHandover(int srcNetworkType, int targetNetworkType,
in ImsReasonInfo reasonInfo);
- void callSessionHandoverFailed(int srcAccessTech, int targetAccessTech,
+ void callSessionHandoverFailed(int srcNetworkType, int targetNetworkType,
in ImsReasonInfo reasonInfo);
- void callSessionMayHandover(int srcAccessTech, int targetAccessTech);
+ void callSessionMayHandover(int srcNetworkType, int targetNetworkType);
/**
* Notifies the TTY mode change by remote party.
diff --git a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
index acab738..75bd6a7 100644
--- a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
+++ b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
@@ -20,6 +20,7 @@
import android.os.Message;
import android.os.RemoteException;
import android.telephony.CallQuality;
+import android.telephony.ServiceState;
import android.telephony.ims.ImsCallProfile;
import android.telephony.ims.ImsCallSession;
import android.telephony.ims.ImsConferenceState;
@@ -547,19 +548,25 @@
@Override
public void callSessionHandover(IImsCallSession i, int srcAccessTech, int targetAccessTech,
ImsReasonInfo reasonInfo) throws RemoteException {
- mNewListener.callSessionHandover(srcAccessTech, targetAccessTech, reasonInfo);
+ mNewListener.callSessionHandover(
+ ServiceState.rilRadioTechnologyToNetworkType(srcAccessTech),
+ ServiceState.rilRadioTechnologyToNetworkType(targetAccessTech), reasonInfo);
}
@Override
public void callSessionHandoverFailed(IImsCallSession i, int srcAccessTech,
int targetAccessTech, ImsReasonInfo reasonInfo) throws RemoteException {
- mNewListener.callSessionHandoverFailed(srcAccessTech, targetAccessTech, reasonInfo);
+ mNewListener.callSessionHandoverFailed(
+ ServiceState.rilRadioTechnologyToNetworkType(srcAccessTech),
+ ServiceState.rilRadioTechnologyToNetworkType(targetAccessTech), reasonInfo);
}
@Override
public void callSessionMayHandover(IImsCallSession i, int srcAccessTech, int targetAccessTech)
throws RemoteException {
- mNewListener.callSessionMayHandover(srcAccessTech, targetAccessTech);
+ mNewListener.callSessionMayHandover(
+ ServiceState.rilRadioTechnologyToNetworkType(srcAccessTech),
+ ServiceState.rilRadioTechnologyToNetworkType(targetAccessTech));
}
@Override
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 099cbff..8fc8af9 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -12,9 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+filegroup {
+ name: "framework-wifi-updatable-exported-aidl-sources",
+ srcs: ["aidl-export/**/*.aidl"],
+ path: "aidl-export",
+ visibility: ["//visibility:private"],
+}
filegroup {
- name: "framework-wifi-updatable-sources",
+ name: "framework-wifi-updatable-java-sources",
srcs: [
"java/**/*.java",
"java/**/*.aidl",
@@ -23,6 +29,15 @@
":framework-wifi-non-updatable-sources"
],
path: "java",
+ visibility: ["//visibility:private"],
+}
+
+filegroup {
+ name: "framework-wifi-updatable-sources",
+ srcs: [
+ ":framework-wifi-updatable-java-sources",
+ ":framework-wifi-updatable-exported-aidl-sources",
+ ],
}
filegroup {
diff --git a/wifi/java/android/net/wifi/ScanResult.aidl b/wifi/aidl-export/android/net/wifi/ScanResult.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/ScanResult.aidl
rename to wifi/aidl-export/android/net/wifi/ScanResult.aidl
diff --git a/wifi/java/android/net/wifi/SoftApCapability.aidl b/wifi/aidl-export/android/net/wifi/SoftApCapability.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/SoftApCapability.aidl
rename to wifi/aidl-export/android/net/wifi/SoftApCapability.aidl
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.aidl b/wifi/aidl-export/android/net/wifi/SoftApConfiguration.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/SoftApConfiguration.aidl
rename to wifi/aidl-export/android/net/wifi/SoftApConfiguration.aidl
diff --git a/wifi/java/android/net/wifi/SoftApInfo.aidl b/wifi/aidl-export/android/net/wifi/SoftApInfo.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/SoftApInfo.aidl
rename to wifi/aidl-export/android/net/wifi/SoftApInfo.aidl
diff --git a/wifi/java/android/net/wifi/WifiClient.aidl b/wifi/aidl-export/android/net/wifi/WifiClient.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/WifiClient.aidl
rename to wifi/aidl-export/android/net/wifi/WifiClient.aidl
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.aidl b/wifi/aidl-export/android/net/wifi/WifiConfiguration.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/WifiConfiguration.aidl
rename to wifi/aidl-export/android/net/wifi/WifiConfiguration.aidl
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.aidl b/wifi/aidl-export/android/net/wifi/WifiEnterpriseConfig.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/WifiEnterpriseConfig.aidl
rename to wifi/aidl-export/android/net/wifi/WifiEnterpriseConfig.aidl
diff --git a/wifi/java/android/net/wifi/WifiInfo.aidl b/wifi/aidl-export/android/net/wifi/WifiInfo.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/WifiInfo.aidl
rename to wifi/aidl-export/android/net/wifi/WifiInfo.aidl
diff --git a/wifi/java/android/net/wifi/WifiNetworkConnectionStatistics.aidl b/wifi/aidl-export/android/net/wifi/WifiNetworkConnectionStatistics.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/WifiNetworkConnectionStatistics.aidl
rename to wifi/aidl-export/android/net/wifi/WifiNetworkConnectionStatistics.aidl
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.aidl b/wifi/aidl-export/android/net/wifi/WifiNetworkSuggestion.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/WifiNetworkSuggestion.aidl
rename to wifi/aidl-export/android/net/wifi/WifiNetworkSuggestion.aidl
diff --git a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.aidl b/wifi/aidl-export/android/net/wifi/WifiUsabilityStatsEntry.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/WifiUsabilityStatsEntry.aidl
rename to wifi/aidl-export/android/net/wifi/WifiUsabilityStatsEntry.aidl
diff --git a/wifi/java/android/net/wifi/WpsInfo.aidl b/wifi/aidl-export/android/net/wifi/WpsInfo.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/WpsInfo.aidl
rename to wifi/aidl-export/android/net/wifi/WpsInfo.aidl
diff --git a/wifi/java/android/net/wifi/aware/Characteristics.aidl b/wifi/aidl-export/android/net/wifi/aware/Characteristics.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/aware/Characteristics.aidl
rename to wifi/aidl-export/android/net/wifi/aware/Characteristics.aidl
diff --git a/wifi/java/android/net/wifi/aware/PublishConfig.aidl b/wifi/aidl-export/android/net/wifi/aware/PublishConfig.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/aware/PublishConfig.aidl
rename to wifi/aidl-export/android/net/wifi/aware/PublishConfig.aidl
diff --git a/wifi/java/android/net/wifi/aware/SubscribeConfig.aidl b/wifi/aidl-export/android/net/wifi/aware/SubscribeConfig.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/aware/SubscribeConfig.aidl
rename to wifi/aidl-export/android/net/wifi/aware/SubscribeConfig.aidl
diff --git a/wifi/java/android/net/wifi/hotspot2/OsuProvider.aidl b/wifi/aidl-export/android/net/wifi/hotspot2/OsuProvider.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/hotspot2/OsuProvider.aidl
rename to wifi/aidl-export/android/net/wifi/hotspot2/OsuProvider.aidl
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.aidl b/wifi/aidl-export/android/net/wifi/hotspot2/PasspointConfiguration.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.aidl
rename to wifi/aidl-export/android/net/wifi/hotspot2/PasspointConfiguration.aidl
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.aidl b/wifi/aidl-export/android/net/wifi/hotspot2/pps/Credential.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/hotspot2/pps/Credential.aidl
rename to wifi/aidl-export/android/net/wifi/hotspot2/pps/Credential.aidl
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.aidl b/wifi/aidl-export/android/net/wifi/hotspot2/pps/HomeSp.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/hotspot2/pps/HomeSp.aidl
rename to wifi/aidl-export/android/net/wifi/hotspot2/pps/HomeSp.aidl
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.aidl b/wifi/aidl-export/android/net/wifi/p2p/WifiP2pConfig.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/p2p/WifiP2pConfig.aidl
rename to wifi/aidl-export/android/net/wifi/p2p/WifiP2pConfig.aidl
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.aidl b/wifi/aidl-export/android/net/wifi/p2p/WifiP2pDevice.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/p2p/WifiP2pDevice.aidl
rename to wifi/aidl-export/android/net/wifi/p2p/WifiP2pDevice.aidl
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.aidl b/wifi/aidl-export/android/net/wifi/p2p/WifiP2pDeviceList.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.aidl
rename to wifi/aidl-export/android/net/wifi/p2p/WifiP2pDeviceList.aidl
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.aidl b/wifi/aidl-export/android/net/wifi/p2p/WifiP2pGroup.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/p2p/WifiP2pGroup.aidl
rename to wifi/aidl-export/android/net/wifi/p2p/WifiP2pGroup.aidl
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pInfo.aidl b/wifi/aidl-export/android/net/wifi/p2p/WifiP2pInfo.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/p2p/WifiP2pInfo.aidl
rename to wifi/aidl-export/android/net/wifi/p2p/WifiP2pInfo.aidl
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl b/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl
rename to wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.aidl b/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.aidl
rename to wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.aidl
diff --git a/wifi/java/android/net/wifi/rtt/RangingRequest.aidl b/wifi/aidl-export/android/net/wifi/rtt/RangingRequest.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/rtt/RangingRequest.aidl
rename to wifi/aidl-export/android/net/wifi/rtt/RangingRequest.aidl
diff --git a/wifi/java/android/net/wifi/rtt/RangingResult.aidl b/wifi/aidl-export/android/net/wifi/rtt/RangingResult.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/rtt/RangingResult.aidl
rename to wifi/aidl-export/android/net/wifi/rtt/RangingResult.aidl
diff --git a/wifi/java/android/net/wifi/rtt/ResponderConfig.aidl b/wifi/aidl-export/android/net/wifi/rtt/ResponderConfig.aidl
similarity index 100%
rename from wifi/java/android/net/wifi/rtt/ResponderConfig.aidl
rename to wifi/aidl-export/android/net/wifi/rtt/ResponderConfig.aidl
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index e84369f..e2befeb 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -402,29 +402,29 @@
public static final String[] strings = { "current", "disabled", "enabled" };
}
- /**
- * Security types we support.
- */
- /** @hide */
+ /** Security type for an open network. */
public static final int SECURITY_TYPE_OPEN = 0;
- /** @hide */
+ /** Security type for a WEP network. */
public static final int SECURITY_TYPE_WEP = 1;
- /** @hide */
+ /** Security type for a PSK network. */
public static final int SECURITY_TYPE_PSK = 2;
- /** @hide */
+ /** Security type for an EAP network. */
public static final int SECURITY_TYPE_EAP = 3;
- /** @hide */
+ /** Security type for an SAE network. */
public static final int SECURITY_TYPE_SAE = 4;
- /** @hide */
+ /** Security type for an EAP Suite B network. */
public static final int SECURITY_TYPE_EAP_SUITE_B = 5;
- /** @hide */
+ /** Security type for an OWE network. */
public static final int SECURITY_TYPE_OWE = 6;
- /** @hide */
+ /** Security type for a WAPI PSK network. */
public static final int SECURITY_TYPE_WAPI_PSK = 7;
- /** @hide */
+ /** Security type for a WAPI Certificate network. */
public static final int SECURITY_TYPE_WAPI_CERT = 8;
- /** @hide */
+ /**
+ * Security types we support.
+ * @hide
+ */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "SECURITY_TYPE_" }, value = {
SECURITY_TYPE_OPEN,
@@ -440,10 +440,19 @@
public @interface SecurityType {}
/**
- * @hide
- * Set security params (sets the various bitsets exposed in WifiConfiguration).
+ * Set the various security params to correspond to the provided security type.
+ * This is accomplished by setting the various BitSets exposed in WifiConfiguration.
*
- * @param securityType One of the security types from {@link SecurityType}.
+ * @param securityType One of the following security types:
+ * {@link #SECURITY_TYPE_OPEN},
+ * {@link #SECURITY_TYPE_WEP},
+ * {@link #SECURITY_TYPE_PSK},
+ * {@link #SECURITY_TYPE_EAP},
+ * {@link #SECURITY_TYPE_SAE},
+ * {@link #SECURITY_TYPE_EAP_SUITE_B},
+ * {@link #SECURITY_TYPE_OWE},
+ * {@link #SECURITY_TYPE_WAPI_PSK}, or
+ * {@link #SECURITY_TYPE_WAPI_CERT}
*/
public void setSecurityParams(@SecurityType int securityType) {
// Clear all the bitsets.