Merge "Add metrics constant for wifi scanning dialog" into pi-dev
diff --git a/Android.bp b/Android.bp
index ce93568..9c76e14 100644
--- a/Android.bp
+++ b/Android.bp
@@ -145,7 +145,7 @@
":libcamera_client_framework_aidl",
"core/java/android/hardware/IConsumerIrService.aidl",
"core/java/android/hardware/ISerialManager.aidl",
- "core/java/android/hardware/biometrics/IBiometricDialogReceiver.aidl",
+ "core/java/android/hardware/biometrics/IBiometricPromptReceiver.aidl",
"core/java/android/hardware/display/IDisplayManager.aidl",
"core/java/android/hardware/display/IDisplayManagerCallback.aidl",
"core/java/android/hardware/display/IVirtualDisplayCallback.aidl",
diff --git a/api/current.txt b/api/current.txt
index ff44ba2..c351bee 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -13658,17 +13658,17 @@
method public static android.graphics.drawable.Drawable decodeDrawable(android.graphics.ImageDecoder.Source, android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException;
method public static android.graphics.drawable.Drawable decodeDrawable(android.graphics.ImageDecoder.Source) throws java.io.IOException;
method public int getAllocator();
- method public boolean getConserveMemory();
method public android.graphics.Rect getCrop();
+ method public int getMemorySizePolicy();
method public android.graphics.ImageDecoder.OnPartialImageListener getOnPartialImageListener();
method public android.graphics.PostProcessor getPostProcessor();
method public boolean isDecodeAsAlphaMaskEnabled();
method public boolean isMutableRequired();
method public boolean isUnpremultipliedRequired();
method public void setAllocator(int);
- method public void setConserveMemory(boolean);
method public void setCrop(android.graphics.Rect);
method public void setDecodeAsAlphaMaskEnabled(boolean);
+ method public void setMemorySizePolicy(int);
method public void setMutableRequired(boolean);
method public void setOnPartialImageListener(android.graphics.ImageDecoder.OnPartialImageListener);
method public void setPostProcessor(android.graphics.PostProcessor);
@@ -13680,6 +13680,8 @@
field public static final int ALLOCATOR_HARDWARE = 3; // 0x3
field public static final int ALLOCATOR_SHARED_MEMORY = 2; // 0x2
field public static final int ALLOCATOR_SOFTWARE = 1; // 0x1
+ field public static final int MEMORY_POLICY_DEFAULT = 1; // 0x1
+ field public static final int MEMORY_POLICY_LOW_RAM = 0; // 0x0
}
public static final class ImageDecoder.DecodeException extends java.io.IOException {
@@ -15756,9 +15758,9 @@
package android.hardware.biometrics {
- public class BiometricDialog {
- method public void authenticate(android.hardware.biometrics.BiometricDialog.CryptoObject, android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.biometrics.BiometricDialog.AuthenticationCallback);
- method public void authenticate(android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.biometrics.BiometricDialog.AuthenticationCallback);
+ public class BiometricPrompt {
+ method public void authenticate(android.hardware.biometrics.BiometricPrompt.CryptoObject, android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.biometrics.BiometricPrompt.AuthenticationCallback);
+ method public void authenticate(android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.biometrics.BiometricPrompt.AuthenticationCallback);
field public static final int BIOMETRIC_ACQUIRED_GOOD = 0; // 0x0
field public static final int BIOMETRIC_ACQUIRED_IMAGER_DIRTY = 3; // 0x3
field public static final int BIOMETRIC_ACQUIRED_INSUFFICIENT = 2; // 0x2
@@ -15778,31 +15780,31 @@
field public static final int BIOMETRIC_ERROR_VENDOR = 8; // 0x8
}
- public static abstract class BiometricDialog.AuthenticationCallback {
- ctor public BiometricDialog.AuthenticationCallback();
+ public static abstract class BiometricPrompt.AuthenticationCallback {
+ ctor public BiometricPrompt.AuthenticationCallback();
method public void onAuthenticationError(int, java.lang.CharSequence);
method public void onAuthenticationFailed();
method public void onAuthenticationHelp(int, java.lang.CharSequence);
- method public void onAuthenticationSucceeded(android.hardware.biometrics.BiometricDialog.AuthenticationResult);
+ method public void onAuthenticationSucceeded(android.hardware.biometrics.BiometricPrompt.AuthenticationResult);
}
- public static class BiometricDialog.AuthenticationResult {
- method public android.hardware.biometrics.BiometricDialog.CryptoObject getCryptoObject();
+ public static class BiometricPrompt.AuthenticationResult {
+ method public android.hardware.biometrics.BiometricPrompt.CryptoObject getCryptoObject();
}
- public static class BiometricDialog.Builder {
- ctor public BiometricDialog.Builder(android.content.Context);
- method public android.hardware.biometrics.BiometricDialog build();
- method public android.hardware.biometrics.BiometricDialog.Builder setDescription(java.lang.CharSequence);
- method public android.hardware.biometrics.BiometricDialog.Builder setNegativeButton(java.lang.CharSequence, java.util.concurrent.Executor, android.content.DialogInterface.OnClickListener);
- method public android.hardware.biometrics.BiometricDialog.Builder setSubtitle(java.lang.CharSequence);
- method public android.hardware.biometrics.BiometricDialog.Builder setTitle(java.lang.CharSequence);
+ public static class BiometricPrompt.Builder {
+ ctor public BiometricPrompt.Builder(android.content.Context);
+ method public android.hardware.biometrics.BiometricPrompt build();
+ method public android.hardware.biometrics.BiometricPrompt.Builder setDescription(java.lang.CharSequence);
+ method public android.hardware.biometrics.BiometricPrompt.Builder setNegativeButton(java.lang.CharSequence, java.util.concurrent.Executor, android.content.DialogInterface.OnClickListener);
+ method public android.hardware.biometrics.BiometricPrompt.Builder setSubtitle(java.lang.CharSequence);
+ method public android.hardware.biometrics.BiometricPrompt.Builder setTitle(java.lang.CharSequence);
}
- public static final class BiometricDialog.CryptoObject {
- ctor public BiometricDialog.CryptoObject(java.security.Signature);
- ctor public BiometricDialog.CryptoObject(javax.crypto.Cipher);
- ctor public BiometricDialog.CryptoObject(javax.crypto.Mac);
+ public static final class BiometricPrompt.CryptoObject {
+ ctor public BiometricPrompt.CryptoObject(java.security.Signature);
+ ctor public BiometricPrompt.CryptoObject(javax.crypto.Cipher);
+ ctor public BiometricPrompt.CryptoObject(javax.crypto.Mac);
method public javax.crypto.Cipher getCipher();
method public javax.crypto.Mac getMac();
method public java.security.Signature getSignature();
@@ -38461,23 +38463,10 @@
public abstract class ConfirmationCallback {
ctor public ConfirmationCallback();
- method public void onConfirmedByUser(byte[]);
- method public void onDismissedByApplication();
- method public void onDismissedByUser();
- method public void onError(java.lang.Exception);
- }
-
- public class ConfirmationDialog {
- method public void cancelPrompt();
- method public static boolean isSupported();
- method public void presentPrompt(java.util.concurrent.Executor, android.security.ConfirmationCallback) throws android.security.ConfirmationAlreadyPresentingException, android.security.ConfirmationNotAvailableException;
- }
-
- public static class ConfirmationDialog.Builder {
- ctor public ConfirmationDialog.Builder();
- method public android.security.ConfirmationDialog build(android.content.Context);
- method public android.security.ConfirmationDialog.Builder setExtraData(byte[]);
- method public android.security.ConfirmationDialog.Builder setPromptText(java.lang.CharSequence);
+ method public void onCanceled();
+ method public void onConfirmed(byte[]);
+ method public void onDismissed();
+ method public void onError(java.lang.Throwable);
}
public class ConfirmationNotAvailableException extends java.lang.Exception {
@@ -38485,6 +38474,19 @@
ctor public ConfirmationNotAvailableException(java.lang.String);
}
+ public class ConfirmationPrompt {
+ method public void cancelPrompt();
+ method public static boolean isSupported(android.content.Context);
+ method public void presentPrompt(java.util.concurrent.Executor, android.security.ConfirmationCallback) throws android.security.ConfirmationAlreadyPresentingException, android.security.ConfirmationNotAvailableException;
+ }
+
+ public static final class ConfirmationPrompt.Builder {
+ ctor public ConfirmationPrompt.Builder(android.content.Context);
+ method public android.security.ConfirmationPrompt build();
+ method public android.security.ConfirmationPrompt.Builder setExtraData(byte[]);
+ method public android.security.ConfirmationPrompt.Builder setPromptText(java.lang.CharSequence);
+ }
+
public final class KeyChain {
ctor public KeyChain();
method public static void choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, java.lang.String[], java.security.Principal[], java.lang.String, int, java.lang.String);
diff --git a/api/removed.txt b/api/removed.txt
index af2b25e..1d6a8c2 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -178,10 +178,12 @@
public final class ImageDecoder implements java.lang.AutoCloseable {
method public deprecated boolean getAsAlphaMask();
+ method public deprecated boolean getConserveMemory();
method public deprecated boolean getDecodeAsAlphaMask();
method public deprecated boolean getMutable();
method public deprecated boolean getRequireUnpremultiplied();
method public deprecated android.graphics.ImageDecoder setAsAlphaMask(boolean);
+ method public deprecated void setConserveMemory(boolean);
method public deprecated android.graphics.ImageDecoder setDecodeAsAlphaMask(boolean);
method public deprecated android.graphics.ImageDecoder setMutable(boolean);
method public deprecated android.graphics.ImageDecoder setRequireUnpremultiplied(boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index e7761b7..962cbbf 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -163,6 +163,7 @@
field public static final java.lang.String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS";
field public static final java.lang.String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS";
field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
+ field public static final java.lang.String SEND_SHOW_SUSPENDED_APP_DETAILS = "android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS";
field public static final java.lang.String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION";
field public static final java.lang.String SERIAL_PORT = "android.permission.SERIAL_PORT";
field public static final java.lang.String SET_ACTIVITY_WATCHER = "android.permission.SET_ACTIVITY_WATCHER";
@@ -878,6 +879,7 @@
field public static final java.lang.String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
field public static final java.lang.String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE";
field public static final java.lang.String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS";
+ field public static final java.lang.String ACTION_SHOW_SUSPENDED_APP_DETAILS = "android.intent.action.SHOW_SUSPENDED_APP_DETAILS";
field public static final deprecated java.lang.String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
field public static final java.lang.String ACTION_SPLIT_CONFIGURATION_CHANGED = "android.intent.action.SPLIT_CONFIGURATION_CHANGED";
field public static final java.lang.String ACTION_UPGRADE_SETUP = "android.intent.action.UPGRADE_SETUP";
diff --git a/api/test-current.txt b/api/test-current.txt
index 9153a39..4878690 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -467,6 +467,14 @@
}
+package android.media.audiofx {
+
+ public class AudioEffect {
+ field public static final java.util.UUID EFFECT_TYPE_NULL;
+ }
+
+}
+
package android.net {
public final class IpSecManager {
diff --git a/cmds/incidentd/src/PrivacyBuffer.cpp b/cmds/incidentd/src/PrivacyBuffer.cpp
index 6cd2fe1..d753e5e 100644
--- a/cmds/incidentd/src/PrivacyBuffer.cpp
+++ b/cmds/incidentd/src/PrivacyBuffer.cpp
@@ -34,7 +34,7 @@
void PrivacyBuffer::writeFieldOrSkip(uint32_t fieldTag, bool skip) {
uint8_t wireType = read_wire_type(fieldTag);
size_t bytesToWrite = 0;
- uint32_t varint = 0;
+ uint64_t varint = 0;
switch (wireType) {
case WIRE_TYPE_VARINT:
diff --git a/cmds/incidentd/src/Section.h b/cmds/incidentd/src/Section.h
index 34a3613..20ecdb1 100644
--- a/cmds/incidentd/src/Section.h
+++ b/cmds/incidentd/src/Section.h
@@ -31,7 +31,7 @@
namespace os {
namespace incidentd {
-const int64_t REMOTE_CALL_TIMEOUT_MS = 10 * 1000; // 10 seconds
+const int64_t REMOTE_CALL_TIMEOUT_MS = 30 * 1000; // 30 seconds
/**
* Base class for sections
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index a68136b..27bbc4b 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2155,10 +2155,10 @@
public String[] setPackagesSuspended(String[] packageNames, boolean suspended,
PersistableBundle appExtras, PersistableBundle launcherExtras,
String dialogMessage) {
- // TODO (b/75332201): Pass in the dialogMessage and use it in the interceptor dialog
try {
return mPM.setPackagesSuspendedAsUser(packageNames, suspended, appExtras,
- launcherExtras, mContext.getOpPackageName(), mContext.getUserId());
+ launcherExtras, dialogMessage, mContext.getOpPackageName(),
+ mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 000912c..efc9b6d 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2282,6 +2282,28 @@
public static final String ACTION_MY_PACKAGE_SUSPENDED = "android.intent.action.MY_PACKAGE_SUSPENDED";
/**
+ * Activity Action: Started to show more details about why an application was suspended.
+ *
+ * <p>Apps holding {@link android.Manifest.permission#SUSPEND_APPS} must declare an activity
+ * handling this intent and protect it with
+ * {@link android.Manifest.permission#SEND_SHOW_SUSPENDED_APP_DETAILS}.
+ *
+ * <p>Includes an extra {@link #EXTRA_PACKAGE_NAME} which is the name of the suspended package.
+ *
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system.
+ *
+ * @see PackageManager#isPackageSuspended()
+ * @see #ACTION_PACKAGES_SUSPENDED
+ *
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_SHOW_SUSPENDED_APP_DETAILS =
+ "android.intent.action.SHOW_SUSPENDED_APP_DETAILS";
+
+ /**
* Broadcast Action: Sent to a package that has been unsuspended.
*
* <p class="note">This is a protected intent that can only be sent
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 277738b..02ce47b8 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -273,8 +273,8 @@
void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage);
String[] setPackagesSuspendedAsUser(in String[] packageNames, boolean suspended,
- in PersistableBundle launcherExtras, in PersistableBundle appExtras,
- String callingPackage, int userId);
+ in PersistableBundle appExtras, in PersistableBundle launcherExtras,
+ String dialogMessage, String callingPackage, int userId);
boolean isPackageSuspendedForUser(String packageName, int userId);
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 96aa36c..a9d0911 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -191,10 +191,10 @@
/**
* Retrieve launcher extras for a suspended package provided to the system in
* {@link PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle,
- * PersistableBundle, String)}
+ * PersistableBundle, String)}.
*
* @param packageName The package for which to return launcher extras.
- * @param userId The user for which to check,
+ * @param userId The user for which to check.
* @return The launcher extras.
*
* @see PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle,
@@ -214,6 +214,29 @@
public abstract boolean isPackageSuspended(String packageName, int userId);
/**
+ * Get the name of the package that suspended the given package. Packages can be suspended by
+ * device administrators or apps holding {@link android.Manifest.permission#MANAGE_USERS} or
+ * {@link android.Manifest.permission#SUSPEND_APPS}.
+ *
+ * @param suspendedPackage The package that has been suspended.
+ * @param userId The user for which to check.
+ * @return Name of the package that suspended the given package. Returns {@code null} if the
+ * given package is not currently suspended and the platform package name - i.e.
+ * {@code "android"} - if the package was suspended by a device admin.
+ */
+ public abstract String getSuspendingPackage(String suspendedPackage, int userId);
+
+ /**
+ * Get the dialog message to be shown to the user when they try to launch a suspended
+ * application.
+ *
+ * @param suspendedPackage The package that has been suspended.
+ * @param userId The user for which to check.
+ * @return The dialog message to be shown to the user.
+ */
+ public abstract String getSuspendedDialogMessage(String suspendedPackage, int userId);
+
+ /**
* Do a straight uid lookup for the given package/application in the given user.
* @see PackageManager#getPackageUidAsUser(String, int, int)
* @return The app's uid, or < 0 if the package was not found in that user
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index f7b6e09..f471a1d 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -34,6 +34,7 @@
import com.android.internal.util.ArrayUtils;
import java.util.Arrays;
+import java.util.Objects;
/**
* Per-user state information about a package.
@@ -47,6 +48,7 @@
public boolean hidden; // Is the app restricted by owner / admin
public boolean suspended;
public String suspendingPackage;
+ public String dialogMessage; // Message to show when a suspended package launch attempt is made
public PersistableBundle suspendedAppExtras;
public PersistableBundle suspendedLauncherExtras;
public boolean instantApp;
@@ -82,6 +84,7 @@
hidden = o.hidden;
suspended = o.suspended;
suspendingPackage = o.suspendingPackage;
+ dialogMessage = o.dialogMessage;
suspendedAppExtras = o.suspendedAppExtras;
suspendedLauncherExtras = o.suspendedLauncherExtras;
instantApp = o.instantApp;
@@ -208,6 +211,9 @@
|| !suspendingPackage.equals(oldState.suspendingPackage)) {
return false;
}
+ if (!Objects.equals(dialogMessage, oldState.dialogMessage)) {
+ return false;
+ }
if (!BaseBundle.kindofEquals(suspendedAppExtras,
oldState.suspendedAppExtras)) {
return false;
diff --git a/core/java/android/hardware/biometrics/BiometricDialog.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
similarity index 93%
rename from core/java/android/hardware/biometrics/BiometricDialog.java
rename to core/java/android/hardware/biometrics/BiometricPrompt.java
index dd848a3..1c9de45 100644
--- a/core/java/android/hardware/biometrics/BiometricDialog.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -38,7 +38,7 @@
/**
* A class that manages a system-provided biometric dialog.
*/
-public class BiometricDialog implements BiometricAuthenticator, BiometricConstants {
+public class BiometricPrompt implements BiometricAuthenticator, BiometricConstants {
/**
* @hide
@@ -190,11 +190,11 @@
}
/**
- * Creates a {@link BiometricDialog}.
- * @return a {@link BiometricDialog}
+ * Creates a {@link BiometricPrompt}.
+ * @return a {@link BiometricPrompt}
* @throws IllegalArgumentException if any of the required fields are not set.
*/
- public BiometricDialog build() {
+ public BiometricPrompt build() {
final CharSequence title = mBundle.getCharSequence(KEY_TITLE);
final CharSequence negative = mBundle.getCharSequence(KEY_NEGATIVE_TEXT);
@@ -203,7 +203,7 @@
} else if (TextUtils.isEmpty(negative)) {
throw new IllegalArgumentException("Negative text must be set and non-empty");
}
- return new BiometricDialog(mContext, mBundle, mPositiveButtonInfo, mNegativeButtonInfo);
+ return new BiometricPrompt(mContext, mBundle, mPositiveButtonInfo, mNegativeButtonInfo);
}
}
@@ -213,7 +213,7 @@
private ButtonInfo mPositiveButtonInfo;
private ButtonInfo mNegativeButtonInfo;
- IBiometricDialogReceiver mDialogReceiver = new IBiometricDialogReceiver.Stub() {
+ IBiometricPromptReceiver mDialogReceiver = new IBiometricPromptReceiver.Stub() {
@Override
public void onDialogDismissed(int reason) {
// Check the reason and invoke OnClickListener(s) if necessary
@@ -229,7 +229,7 @@
}
};
- private BiometricDialog(Context context, Bundle bundle,
+ private BiometricPrompt(Context context, Bundle bundle,
ButtonInfo positiveButtonInfo, ButtonInfo negativeButtonInfo) {
mBundle = bundle;
mPositiveButtonInfo = positiveButtonInfo;
@@ -239,7 +239,7 @@
}
/**
- * A wrapper class for the crypto objects supported by BiometricDialog. Currently the framework
+ * A wrapper class for the crypto objects supported by BiometricPrompt. Currently the framework
* supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
*/
public static final class CryptoObject extends android.hardware.biometrics.CryptoObject {
@@ -308,8 +308,8 @@
}
/**
- * Callback structure provided to {@link BiometricDialog#authenticate(CancellationSignal,
- * Executor, AuthenticationCallback)} or {@link BiometricDialog#authenticate(CryptoObject,
+ * Callback structure provided to {@link BiometricPrompt#authenticate(CancellationSignal,
+ * Executor, AuthenticationCallback)} or {@link BiometricPrompt#authenticate(CryptoObject,
* CancellationSignal, Executor, AuthenticationCallback)}. Users must provide an implementation
* of this for listening to authentication events.
*/
@@ -378,7 +378,7 @@
@NonNull CancellationSignal cancel,
@NonNull @CallbackExecutor Executor executor,
@NonNull BiometricAuthenticator.AuthenticationCallback callback) {
- if (!(callback instanceof BiometricDialog.AuthenticationCallback)) {
+ if (!(callback instanceof BiometricPrompt.AuthenticationCallback)) {
throw new IllegalArgumentException("Callback cannot be casted");
}
authenticate(crypto, cancel, executor, (AuthenticationCallback) callback);
@@ -395,7 +395,7 @@
public void authenticate(@NonNull CancellationSignal cancel,
@NonNull @CallbackExecutor Executor executor,
@NonNull BiometricAuthenticator.AuthenticationCallback callback) {
- if (!(callback instanceof BiometricDialog.AuthenticationCallback)) {
+ if (!(callback instanceof BiometricPrompt.AuthenticationCallback)) {
throw new IllegalArgumentException("Callback cannot be casted");
}
authenticate(cancel, executor, (AuthenticationCallback) callback);
@@ -410,8 +410,8 @@
* operation can be canceled by using the provided cancel object. The application will receive
* authentication errors through {@link AuthenticationCallback}, and button events through the
* corresponding callback set in {@link Builder#setNegativeButton(CharSequence, Executor,
- * DialogInterface.OnClickListener)}. It is safe to reuse the {@link BiometricDialog} object,
- * and calling {@link BiometricDialog#authenticate( CancellationSignal, Executor,
+ * DialogInterface.OnClickListener)}. It is safe to reuse the {@link BiometricPrompt} object,
+ * and calling {@link BiometricPrompt#authenticate( CancellationSignal, Executor,
* AuthenticationCallback)} while an existing authentication attempt is occurring will stop the
* previous client and start a new authentication. The interrupted client will receive a
* cancelled notification through {@link AuthenticationCallback#onAuthenticationError(int,
@@ -445,8 +445,8 @@
* provided cancel object. The application will receive authentication errors through {@link
* AuthenticationCallback}, and button events through the corresponding callback set in {@link
* Builder#setNegativeButton(CharSequence, Executor, DialogInterface.OnClickListener)}. It is
- * safe to reuse the {@link BiometricDialog} object, and calling {@link
- * BiometricDialog#authenticate(CancellationSignal, Executor, AuthenticationCallback)} while
+ * safe to reuse the {@link BiometricPrompt} object, and calling {@link
+ * BiometricPrompt#authenticate(CancellationSignal, Executor, AuthenticationCallback)} while
* an existing authentication attempt is occurring will stop the previous client and start a new
* authentication. The interrupted client will receive a cancelled notification through {@link
* AuthenticationCallback#onAuthenticationError(int, CharSequence)}.
@@ -470,15 +470,15 @@
private boolean handlePreAuthenticationErrors(AuthenticationCallback callback,
Executor executor) {
if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
- sendError(BiometricDialog.BIOMETRIC_ERROR_HW_NOT_PRESENT, callback,
+ sendError(BiometricPrompt.BIOMETRIC_ERROR_HW_NOT_PRESENT, callback,
executor);
return true;
} else if (!mFingerprintManager.isHardwareDetected()) {
- sendError(BiometricDialog.BIOMETRIC_ERROR_HW_UNAVAILABLE, callback,
+ sendError(BiometricPrompt.BIOMETRIC_ERROR_HW_UNAVAILABLE, callback,
executor);
return true;
} else if (!mFingerprintManager.hasEnrolledFingerprints()) {
- sendError(BiometricDialog.BIOMETRIC_ERROR_NO_BIOMETRICS, callback,
+ sendError(BiometricPrompt.BIOMETRIC_ERROR_NO_BIOMETRICS, callback,
executor);
return true;
}
diff --git a/core/java/android/hardware/biometrics/IBiometricDialogReceiver.aidl b/core/java/android/hardware/biometrics/IBiometricPromptReceiver.aidl
similarity index 87%
rename from core/java/android/hardware/biometrics/IBiometricDialogReceiver.aidl
rename to core/java/android/hardware/biometrics/IBiometricPromptReceiver.aidl
index e528aa7..67c9346 100644
--- a/core/java/android/hardware/biometrics/IBiometricDialogReceiver.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricPromptReceiver.aidl
@@ -19,9 +19,9 @@
import android.os.UserHandle;
/**
- * Communication channel from the BiometricDialog (SysUI) back to AuthenticationClient.
+ * Communication channel from the BiometricPrompt (SysUI) back to AuthenticationClient.
* @hide
*/
-oneway interface IBiometricDialogReceiver {
+oneway interface IBiometricPromptReceiver {
void onDialogDismissed(int reason);
}
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index a6c8c67..40d31bf 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -31,9 +31,9 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.biometrics.BiometricAuthenticator;
-import android.hardware.biometrics.BiometricDialog;
import android.hardware.biometrics.BiometricFingerprintConstants;
-import android.hardware.biometrics.IBiometricDialogReceiver;
+import android.hardware.biometrics.BiometricPrompt;
+import android.hardware.biometrics.IBiometricPromptReceiver;
import android.os.Binder;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -57,7 +57,7 @@
/**
* A class that coordinates access to the fingerprint hardware.
- * @deprecated See {@link BiometricDialog} which shows a system-provided dialog upon starting
+ * @deprecated See {@link BiometricPrompt} which shows a system-provided dialog upon starting
* authentication. In a world where devices may have different types of biometric authentication,
* it's much more realistic to have a system-provided authentication dialog since the method may
* vary by vendor/device.
@@ -111,7 +111,7 @@
/**
* A wrapper class for the crypto objects supported by FingerprintManager. Currently the
* framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
- * @deprecated See {@link android.hardware.biometrics.BiometricDialog.CryptoObject}
+ * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.CryptoObject}
*/
@Deprecated
public static final class CryptoObject extends android.hardware.biometrics.CryptoObject {
@@ -155,7 +155,7 @@
/**
* Container for callback data from {@link FingerprintManager#authenticate(CryptoObject,
* CancellationSignal, int, AuthenticationCallback, Handler)}.
- * @deprecated See {@link android.hardware.biometrics.BiometricDialog.AuthenticationResult}
+ * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationResult}
*/
@Deprecated
public static class AuthenticationResult {
@@ -204,7 +204,7 @@
* FingerprintManager#authenticate(CryptoObject, CancellationSignal,
* int, AuthenticationCallback, Handler) } must provide an implementation of this for listening to
* fingerprint events.
- * @deprecated See {@link android.hardware.biometrics.BiometricDialog.AuthenticationCallback}
+ * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationCallback}
*/
@Deprecated
public static abstract class AuthenticationCallback
@@ -378,10 +378,10 @@
* by <a href="{@docRoot}training/articles/keystore.html">Android Keystore
* facility</a>.
* @throws IllegalStateException if the crypto primitive is not initialized.
- * @deprecated See {@link BiometricDialog#authenticate(CancellationSignal, Executor,
- * BiometricDialog.AuthenticationCallback)} and {@link BiometricDialog#authenticate(
- * BiometricDialog.CryptoObject, CancellationSignal, Executor,
- * BiometricDialog.AuthenticationCallback)}
+ * @deprecated See {@link BiometricPrompt#authenticate(CancellationSignal, Executor,
+ * BiometricPrompt.AuthenticationCallback)} and {@link BiometricPrompt#authenticate(
+ * BiometricPrompt.CryptoObject, CancellationSignal, Executor,
+ * BiometricPrompt.AuthenticationCallback)}
*/
@Deprecated
@RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
@@ -444,7 +444,7 @@
/**
* Per-user version, see {@link FingerprintManager#authenticate(CryptoObject,
- * CancellationSignal, Bundle, Executor, IBiometricDialogReceiver, AuthenticationCallback)}
+ * CancellationSignal, Bundle, Executor, IBiometricPromptReceiver, AuthenticationCallback)}
* @param userId the user ID that the fingerprint hardware will authenticate for.
*/
private void authenticate(int userId,
@@ -452,7 +452,7 @@
@NonNull CancellationSignal cancel,
@NonNull Bundle bundle,
@NonNull @CallbackExecutor Executor executor,
- @NonNull IBiometricDialogReceiver receiver,
+ @NonNull IBiometricPromptReceiver receiver,
@NonNull BiometricAuthenticator.AuthenticationCallback callback) {
mCryptoObject = crypto;
if (cancel.isCanceled()) {
@@ -480,8 +480,8 @@
}
/**
- * Private method, see {@link BiometricDialog#authenticate(CancellationSignal, Executor,
- * BiometricDialog.AuthenticationCallback)}
+ * Private method, see {@link BiometricPrompt#authenticate(CancellationSignal, Executor,
+ * BiometricPrompt.AuthenticationCallback)}
* @param cancel
* @param executor
* @param callback
@@ -491,7 +491,7 @@
@NonNull CancellationSignal cancel,
@NonNull Bundle bundle,
@NonNull @CallbackExecutor Executor executor,
- @NonNull IBiometricDialogReceiver receiver,
+ @NonNull IBiometricPromptReceiver receiver,
@NonNull BiometricAuthenticator.AuthenticationCallback callback) {
if (cancel == null) {
throw new IllegalArgumentException("Must supply a cancellation signal");
@@ -512,8 +512,8 @@
}
/**
- * Private method, see {@link BiometricDialog#authenticate(BiometricDialog.CryptoObject,
- * CancellationSignal, Executor, BiometricDialog.AuthenticationCallback)}
+ * Private method, see {@link BiometricPrompt#authenticate(BiometricPrompt.CryptoObject,
+ * CancellationSignal, Executor, BiometricPrompt.AuthenticationCallback)}
* @param crypto
* @param cancel
* @param executor
@@ -524,7 +524,7 @@
@NonNull CancellationSignal cancel,
@NonNull Bundle bundle,
@NonNull @CallbackExecutor Executor executor,
- @NonNull IBiometricDialogReceiver receiver,
+ @NonNull IBiometricPromptReceiver receiver,
@NonNull BiometricAuthenticator.AuthenticationCallback callback) {
if (crypto == null) {
throw new IllegalArgumentException("Must supply a crypto object");
@@ -743,7 +743,7 @@
* Determine if there is at least one fingerprint enrolled.
*
* @return true if at least one fingerprint is enrolled, false otherwise
- * @deprecated See {@link BiometricDialog} and
+ * @deprecated See {@link BiometricPrompt} and
* {@link FingerprintManager#FINGERPRINT_ERROR_NO_FINGERPRINTS}
*/
@Deprecated
@@ -777,7 +777,7 @@
* Determine if fingerprint hardware is present and functional.
*
* @return true if hardware is present and functional, false otherwise.
- * @deprecated See {@link BiometricDialog} and
+ * @deprecated See {@link BiometricPrompt} and
* {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE}
*/
@Deprecated
@@ -1158,7 +1158,7 @@
@Override // binder call
public void onError(long deviceId, int error, int vendorCode) {
if (mExecutor != null) {
- // BiometricDialog case
+ // BiometricPrompt case
if (error == FingerprintManager.FINGERPRINT_ERROR_USER_CANCELED) {
// User tapped somewhere to cancel, the biometric dialog is already dismissed.
mExecutor.execute(() -> {
@@ -1172,7 +1172,7 @@
mExecutor.execute(() -> {
sendErrorResult(deviceId, error, vendorCode);
});
- }, BiometricDialog.HIDE_DIALOG_DELAY);
+ }, BiometricPrompt.HIDE_DIALOG_DELAY);
}
} else {
mHandler.obtainMessage(MSG_ERROR, error, vendorCode, deviceId).sendToTarget();
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 78d01e5..8aa2183 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -16,7 +16,7 @@
package android.hardware.fingerprint;
import android.os.Bundle;
-import android.hardware.biometrics.IBiometricDialogReceiver;
+import android.hardware.biometrics.IBiometricPromptReceiver;
import android.hardware.fingerprint.IFingerprintClientActiveCallback;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
@@ -31,7 +31,7 @@
// Authenticate the given sessionId with a fingerprint
void authenticate(IBinder token, long sessionId, int userId,
IFingerprintServiceReceiver receiver, int flags, String opPackageName,
- in Bundle bundle, IBiometricDialogReceiver dialogReceiver);
+ in Bundle bundle, IBiometricPromptReceiver dialogReceiver);
// Cancel authentication for the given sessionId
void cancelAuthentication(IBinder token, String opPackageName);
diff --git a/core/java/android/security/ConfirmationCallback.java b/core/java/android/security/ConfirmationCallback.java
index 4670bce..fd027f0 100644
--- a/core/java/android/security/ConfirmationCallback.java
+++ b/core/java/android/security/ConfirmationCallback.java
@@ -33,22 +33,22 @@
*
* @param dataThatWasConfirmed the data that was confirmed, see above for the format.
*/
- public void onConfirmedByUser(@NonNull byte[] dataThatWasConfirmed) {}
+ public void onConfirmed(@NonNull byte[] dataThatWasConfirmed) {}
/**
* Called when the requested prompt was dismissed (not accepted) by the user.
*/
- public void onDismissedByUser() {}
+ public void onDismissed() {}
/**
* Called when the requested prompt was dismissed by the application.
*/
- public void onDismissedByApplication() {}
+ public void onCanceled() {}
/**
* Called when the requested prompt was dismissed because of a low-level error.
*
- * @param e an exception representing the error.
+ * @param e a throwable representing the error.
*/
- public void onError(Exception e) {}
+ public void onError(Throwable e) {}
}
diff --git a/core/java/android/security/ConfirmationDialog.java b/core/java/android/security/ConfirmationPrompt.java
similarity index 88%
rename from core/java/android/security/ConfirmationDialog.java
rename to core/java/android/security/ConfirmationPrompt.java
index 1697106..5330cff 100644
--- a/core/java/android/security/ConfirmationDialog.java
+++ b/core/java/android/security/ConfirmationPrompt.java
@@ -68,7 +68,7 @@
* {@link #presentPrompt presentPrompt()} method. The <i>Relying Party</i> stores the nonce locally
* since it'll use it in a later step.
* <li> If the user approves the prompt a <i>Confirmation Response</i> is returned in the
- * {@link ConfirmationCallback#onConfirmedByUser onConfirmedByUser(byte[])} callback as the
+ * {@link ConfirmationCallback#onConfirmed onConfirmed(byte[])} callback as the
* <code>dataThatWasConfirmed</code> parameter. This blob contains the text that was shown to the
* user, the <code>extraData</code> parameter, and possibly other data.
* <li> The application signs the <i>Confirmation Response</i> with the previously created key and
@@ -82,8 +82,8 @@
* last bullet, is to have the <i>Relying Party</i> generate <code>promptText</code> and store it
* along the nonce in the <code>extraData</code> blob.
*/
-public class ConfirmationDialog {
- private static final String TAG = "ConfirmationDialog";
+public class ConfirmationPrompt {
+ private static final String TAG = "ConfirmationPrompt";
private CharSequence mPromptText;
private byte[] mExtraData;
@@ -97,15 +97,15 @@
ConfirmationCallback callback) {
switch (responseCode) {
case KeyStore.CONFIRMATIONUI_OK:
- callback.onConfirmedByUser(dataThatWasConfirmed);
+ callback.onConfirmed(dataThatWasConfirmed);
break;
case KeyStore.CONFIRMATIONUI_CANCELED:
- callback.onDismissedByUser();
+ callback.onDismissed();
break;
case KeyStore.CONFIRMATIONUI_ABORTED:
- callback.onDismissedByApplication();
+ callback.onCanceled();
break;
case KeyStore.CONFIRMATIONUI_SYSTEM_ERROR:
@@ -145,21 +145,25 @@
};
/**
- * A builder that collects arguments, to be shown on the system-provided confirmation dialog.
+ * A builder that collects arguments, to be shown on the system-provided confirmation prompt.
*/
- public static class Builder {
+ public static final class Builder {
+ private Context mContext;
private CharSequence mPromptText;
private byte[] mExtraData;
/**
- * Creates a builder for the confirmation dialog.
+ * Creates a builder for the confirmation prompt.
+ *
+ * @param context the application context
*/
- public Builder() {
+ public Builder(Context context) {
+ mContext = context;
}
/**
- * Sets the prompt text for the dialog.
+ * Sets the prompt text for the prompt.
*
* @param promptText the text to present in the prompt.
* @return the builder.
@@ -170,7 +174,7 @@
}
/**
- * Sets the extra data for the dialog.
+ * Sets the extra data for the prompt.
*
* @param extraData data to include in the response data.
* @return the builder.
@@ -181,24 +185,23 @@
}
/**
- * Creates a {@link ConfirmationDialog} with the arguments supplied to this builder.
+ * Creates a {@link ConfirmationPrompt} with the arguments supplied to this builder.
*
- * @param context the application context
- * @return a {@link ConfirmationDialog}
+ * @return a {@link ConfirmationPrompt}
* @throws IllegalArgumentException if any of the required fields are not set.
*/
- public ConfirmationDialog build(Context context) {
+ public ConfirmationPrompt build() {
if (TextUtils.isEmpty(mPromptText)) {
throw new IllegalArgumentException("prompt text must be set and non-empty");
}
if (mExtraData == null) {
throw new IllegalArgumentException("extraData must be set");
}
- return new ConfirmationDialog(context, mPromptText, mExtraData);
+ return new ConfirmationPrompt(mContext, mPromptText, mExtraData);
}
}
- private ConfirmationDialog(Context context, CharSequence promptText, byte[] extraData) {
+ private ConfirmationPrompt(Context context, CharSequence promptText, byte[] extraData) {
mContext = context;
mPromptText = promptText;
mExtraData = extraData;
@@ -227,10 +230,10 @@
return uiOptionsAsFlags;
}
- private boolean isAccessibilityServiceRunning() {
+ private static boolean isAccessibilityServiceRunning(Context context) {
boolean serviceRunning = false;
try {
- ContentResolver contentResolver = mContext.getContentResolver();
+ ContentResolver contentResolver = context.getContentResolver();
int a11yEnabled = Settings.Secure.getInt(contentResolver,
Settings.Secure.ACCESSIBILITY_ENABLED);
if (a11yEnabled == 1) {
@@ -249,12 +252,12 @@
* When the prompt is no longer being presented, one of the methods in
* {@link ConfirmationCallback} is called on the supplied callback object.
*
- * Confirmation dialogs may not be available when accessibility services are running so this
+ * Confirmation prompts may not be available when accessibility services are running so this
* may fail with a {@link ConfirmationNotAvailableException} exception even if
* {@link #isSupported} returns {@code true}.
*
* @param executor the executor identifying the thread that will receive the callback.
- * @param callback the callback to use when the dialog is done showing.
+ * @param callback the callback to use when the prompt is done showing.
* @throws IllegalArgumentException if the prompt text is too long or malfomed.
* @throws ConfirmationAlreadyPresentingException if another prompt is being presented.
* @throws ConfirmationNotAvailableException if confirmation prompts are not supported.
@@ -265,7 +268,7 @@
if (mCallback != null) {
throw new ConfirmationAlreadyPresentingException();
}
- if (isAccessibilityServiceRunning()) {
+ if (isAccessibilityServiceRunning(mContext)) {
throw new ConfirmationNotAvailableException();
}
mCallback = callback;
@@ -301,7 +304,7 @@
* Cancels a prompt currently being displayed.
*
* On success, the
- * {@link ConfirmationCallback#onDismissedByApplication onDismissedByApplication()} method on
+ * {@link ConfirmationCallback#onCanceled onCanceled()} method on
* the supplied callback object will be called asynchronously.
*
* @throws IllegalStateException if no prompt is currently being presented.
@@ -324,9 +327,13 @@
/**
* Checks if the device supports confirmation prompts.
*
+ * @param context the application context.
* @return true if confirmation prompts are supported by the device.
*/
- public static boolean isSupported() {
+ public static boolean isSupported(Context context) {
+ if (isAccessibilityServiceRunning(context)) {
+ return false;
+ }
return KeyStore.getInstance().isConfirmationPromptSupported();
}
}
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index cca66d6..08c2d0b 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -610,6 +610,10 @@
ViewRootImpl root = mRoots.get(i);
// Client might remove the view by "stopped" event.
root.setWindowStopped(stopped);
+ // Recursively forward stopped state to View's attached
+ // to this Window rather than the root application token,
+ // e.g. PopupWindow's.
+ setStoppedState(root.mAttachInfo.mWindowToken, stopped);
}
}
}
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index 4710671..f048d29 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -216,13 +216,17 @@
@IntRange(from = 0) int selectionStartIndex,
@IntRange(from = 0) int selectionEndIndex,
@Nullable TextSelection.Options options) {
- final TextSelection.Request request = options.getRequest() != null
- ? options.getRequest()
- : new TextSelection.Request.Builder(
- text, selectionStartIndex, selectionEndIndex)
- .setDefaultLocales(options.getDefaultLocales())
- .build();
- return suggestSelection(request);
+ if (options == null) {
+ return suggestSelection(new TextSelection.Request.Builder(
+ text, selectionStartIndex, selectionEndIndex).build());
+ } else if (options.getRequest() != null) {
+ return suggestSelection(options.getRequest());
+ } else {
+ return suggestSelection(
+ new TextSelection.Request.Builder(text, selectionStartIndex, selectionEndIndex)
+ .setDefaultLocales(options.getDefaultLocales())
+ .build());
+ }
}
/**
@@ -291,14 +295,17 @@
@IntRange(from = 0) int startIndex,
@IntRange(from = 0) int endIndex,
@Nullable TextClassification.Options options) {
- final TextClassification.Request request = options.getRequest() != null
- ? options.getRequest()
- : new TextClassification.Request.Builder(
- text, startIndex, endIndex)
- .setDefaultLocales(options.getDefaultLocales())
- .setReferenceTime(options.getReferenceTime())
- .build();
- return classifyText(request);
+ if (options == null) {
+ return classifyText(
+ new TextClassification.Request.Builder(text, startIndex, endIndex).build());
+ } else if (options.getRequest() != null) {
+ return classifyText(options.getRequest());
+ } else {
+ return classifyText(new TextClassification.Request.Builder(text, startIndex, endIndex)
+ .setDefaultLocales(options.getDefaultLocales())
+ .setReferenceTime(options.getReferenceTime())
+ .build());
+ }
}
/**
@@ -326,13 +333,16 @@
/** @hide */
default TextLinks generateLinks(
@NonNull CharSequence text, @Nullable TextLinks.Options options) {
- final TextLinks.Request request = options.getRequest() != null
- ? options.getRequest()
- : new TextLinks.Request.Builder(text)
- .setDefaultLocales(options.getDefaultLocales())
- .setEntityConfig(options.getEntityConfig())
- .build();
- return generateLinks(request);
+ if (options == null) {
+ return generateLinks(new TextLinks.Request.Builder(text).build());
+ } else if (options.getRequest() != null) {
+ return generateLinks(options.getRequest());
+ } else {
+ return generateLinks(new TextLinks.Request.Builder(text)
+ .setDefaultLocales(options.getDefaultLocales())
+ .setEntityConfig(options.getEntityConfig())
+ .build());
+ }
}
/**
diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java
new file mode 100644
index 0000000..322c876
--- /dev/null
+++ b/core/java/com/android/internal/app/SuspendedAppActivity.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.util.Slog;
+import android.view.Window;
+import android.view.WindowManager;
+
+import com.android.internal.R;
+
+public class SuspendedAppActivity extends AlertActivity
+ implements DialogInterface.OnClickListener {
+ private static final String TAG = "SuspendedAppActivity";
+
+ public static final String EXTRA_DIALOG_MESSAGE = "SuspendedAppActivity.extra.DIALOG_MESSAGE";
+ public static final String EXTRA_MORE_DETAILS_INTENT =
+ "SuspendedAppActivity.extra.MORE_DETAILS_INTENT";
+
+ private Intent mMoreDetailsIntent;
+ private int mUserId;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ Window window = getWindow();
+ window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
+ super.onCreate(icicle);
+
+ final Intent intent = getIntent();
+ mMoreDetailsIntent = intent.getParcelableExtra(EXTRA_MORE_DETAILS_INTENT);
+ mUserId = intent.getIntExtra(Intent.EXTRA_USER_ID, -1);
+ if (mUserId < 0) {
+ Slog.wtf(TAG, "Invalid user: " + mUserId);
+ finish();
+ return;
+ }
+ String dialogMessage = intent.getStringExtra(EXTRA_DIALOG_MESSAGE);
+ if (dialogMessage == null) {
+ dialogMessage = getString(R.string.app_suspended_default_message);
+ }
+
+ final AlertController.AlertParams ap = mAlertParams;
+ ap.mTitle = getString(R.string.app_suspended_title);
+ ap.mMessage = String.format(getResources().getConfiguration().getLocales().get(0),
+ dialogMessage, intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME));
+ ap.mPositiveButtonText = getString(android.R.string.ok);
+ if (mMoreDetailsIntent != null) {
+ ap.mNeutralButtonText = getString(R.string.app_suspended_more_details);
+ }
+ ap.mPositiveButtonListener = ap.mNeutralButtonListener = this;
+ setupAlert();
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ switch (which) {
+ case AlertDialog.BUTTON_NEUTRAL:
+ startActivityAsUser(mMoreDetailsIntent, UserHandle.of(mUserId));
+ Slog.i(TAG, "Started more details activity");
+ break;
+ }
+ finish();
+ }
+}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index ad5743d..2790324 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -18,7 +18,7 @@
import android.content.ComponentName;
import android.graphics.Rect;
-import android.hardware.biometrics.IBiometricDialogReceiver;
+import android.hardware.biometrics.IBiometricPromptReceiver;
import android.os.Bundle;
import android.service.notification.StatusBarNotification;
@@ -141,7 +141,7 @@
void showShutdownUi(boolean isReboot, String reason);
// Used to show the dialog when FingerprintService starts authentication
- void showFingerprintDialog(in Bundle bundle, IBiometricDialogReceiver receiver);
+ void showFingerprintDialog(in Bundle bundle, IBiometricPromptReceiver receiver);
// Used to hide the dialog when a finger is authenticated
void onFingerprintAuthenticated();
// Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 0c5efe2..24f2fbf 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -20,7 +20,7 @@
import android.graphics.Rect;
import android.os.Bundle;
import android.service.notification.StatusBarNotification;
-import android.hardware.biometrics.IBiometricDialogReceiver;
+import android.hardware.biometrics.IBiometricPromptReceiver;
import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.StatusBarIcon;
@@ -88,7 +88,7 @@
void showPinningEscapeToast();
// Used to show the dialog when FingerprintService starts authentication
- void showFingerprintDialog(in Bundle bundle, IBiometricDialogReceiver receiver);
+ void showFingerprintDialog(in Bundle bundle, IBiometricPromptReceiver receiver);
// Used to hide the dialog when a finger is authenticated
void onFingerprintAuthenticated();
// Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/core/java/com/android/internal/widget/MessagingMessage.java b/core/java/com/android/internal/widget/MessagingMessage.java
index bf1c5ca..a2cc7cf 100644
--- a/core/java/com/android/internal/widget/MessagingMessage.java
+++ b/core/java/com/android/internal/widget/MessagingMessage.java
@@ -16,6 +16,7 @@
package com.android.internal.widget;
+import android.app.ActivityManager;
import android.app.Notification;
import android.view.View;
@@ -33,7 +34,7 @@
static MessagingMessage createMessage(MessagingLayout layout,
Notification.MessagingStyle.Message m) {
- if (hasImage(m)) {
+ if (hasImage(m) && !ActivityManager.isLowRamDeviceStatic()) {
return MessagingImageMessage.createMessage(layout, m);
} else {
return MessagingTextMessage.createMessage(layout, m);
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 6467976..2a7c256 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -170,7 +170,7 @@
];
optional BatteryTypeProto battery_type = 2006 [
- (section).type = SECTION_FILE,
+ (section).type = SECTION_NONE, // disabled since the path is device specific!
(section).args = "/sys/class/power_supply/bms/battery_type"
];
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
index cccd2fe..bcd7f29 100644
--- a/core/proto/android/service/notification.proto
+++ b/core/proto/android/service/notification.proto
@@ -65,7 +65,7 @@
optional bool can_vibrate = 7;
optional bool can_show_light = 8;
optional string group_key = 9 [ (.android.privacy).dest = DEST_EXPLICIT ];
- optional int32 importance = 10;
+ optional sint32 importance = 10;
}
message ListenersDisablingEffectsProto {
@@ -122,11 +122,11 @@
// Default value is UNKNOWN_UID = USER_NULL = -10000.
optional int32 uid = 2;
// Default is IMPORTANCE_UNSPECIFIED (-1000).
- optional int32 importance = 3;
+ optional sint32 importance = 3;
// Default is PRIORITY_DEFAULT (0).
optional int32 priority = 4;
// Default is VISIBILITY_NO_OVERRIDE (-1000).
- optional int32 visibility = 5;
+ optional sint32 visibility = 5;
// Default is true.
optional bool show_badge = 6;
repeated android.app.NotificationChannelProto channels = 7;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b7b5f23..da15506 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2030,6 +2030,15 @@
<permission android:name="android.permission.START_ANY_ACTIVITY"
android:protectionLevel="signature" />
+ <!-- @SystemApi Must be required by activities that handle the intent action
+ {@link Intent#ACTION_SEND_SHOW_SUSPENDED_APP_DETAILS}. This is for use by apps that
+ hold {@link Manifest.permission#SUSPEND_APPS} to interact with the system.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS"
+ android:protectionLevel="signature" />
+ <uses-permission android:name="android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS" />
+
<!-- @deprecated The {@link android.app.ActivityManager#restartPackage}
API is no longer supported. -->
<permission android:name="android.permission.RESTART_PACKAGES"
@@ -4116,6 +4125,12 @@
</intent-filter>
</activity>
+ <activity android:name="com.android.internal.app.SuspendedAppActivity"
+ android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
+ android:excludeFromRecents="true"
+ android:process=":ui">
+ </activity>
+
<activity android:name="com.android.internal.app.UnlaunchableAppActivity"
android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
android:excludeFromRecents="true"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3cd80f2..12e5dfe 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2249,6 +2249,10 @@
mirror the content of the default display. -->
<bool name="config_localDisplaysMirrorContent">true</bool>
+ <!-- Indicates whether local non-default displays are private.
+ {@see android.view.Display#FLAG_PRIVATE} -->
+ <bool name="config_localDisplaysPrivate">false</bool>
+
<!-- The default mode for the default display. One of the following values (See Display.java):
0 - COLOR_MODE_DEFAULT
7 - COLOR_MODE_SRGB
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 17b9d28..715be5b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4703,6 +4703,13 @@
<!-- Menu item in the locale menu [CHAR LIMIT=30] -->
<string name="locale_search_menu">Search</string>
+ <!-- Title of the dialog that is shown when the user tries to launch a suspended application [CHAR LIMIT=30] -->
+ <string name="app_suspended_title">Action not allowed</string>
+ <!-- Default message shown in the dialog that is shown when the user tries to launch a suspended application [CHAR LIMIT=NONE] -->
+ <string name="app_suspended_default_message">The application <xliff:g id="app_name" example="GMail">%1$s</xliff:g> is currently disabled.</string>
+ <!-- Title of the button to show users more details about why the app has been suspended [CHAR LIMIT=50]-->
+ <string name="app_suspended_more_details">More details</string>
+
<!-- Title of a dialog. The string is asking if the user wants to turn on their work profile, which contains work apps that are managed by their employer. "Work" is an adjective. [CHAR LIMIT=30] -->
<string name="work_mode_off_title">Turn on work profile?</string>
<!-- Text in a dialog. This string describes what will happen if a user decides to turn on their work profile. "Work profile" is used as an adjective. [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ac5c3ab..5856648 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -352,6 +352,7 @@
<java-symbol type="bool" name="config_noHomeScreen" />
<java-symbol type="bool" name="config_guestUserEphemeral" />
<java-symbol type="bool" name="config_localDisplaysMirrorContent" />
+ <java-symbol type="bool" name="config_localDisplaysPrivate" />
<java-symbol type="integer" name="config_defaultDisplayDefaultColorMode" />
<java-symbol type="bool" name="config_enableAppWidgetService" />
<java-symbol type="string" name="config_defaultPictureInPictureScreenEdgeInsets" />
@@ -2877,6 +2878,10 @@
<java-symbol type="string" name="suspended_widget_accessibility" />
+ <java-symbol type="string" name="app_suspended_title" />
+ <java-symbol type="string" name="app_suspended_more_details" />
+ <java-symbol type="string" name="app_suspended_default_message" />
+
<!-- Used internally for assistant to launch activity transitions -->
<java-symbol type="id" name="cross_task_transition" />
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 4210c5c..ecd443c 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -581,7 +581,7 @@
/** @removed
* @deprecated Subsumed by {@link #DecodeException}.
*/
- @java.lang.Deprecated
+ @Deprecated
public static class IncompleteException extends IOException {};
/**
@@ -613,19 +613,19 @@
/** @removed
* @deprecated Replaced by {@link #DecodeException#SOURCE_EXCEPTION}.
*/
- @java.lang.Deprecated
+ @Deprecated
public static final int ERROR_SOURCE_EXCEPTION = 1;
/** @removed
* @deprecated Replaced by {@link #DecodeException#SOURCE_INCOMPLETE}.
*/
- @java.lang.Deprecated
+ @Deprecated
public static final int ERROR_SOURCE_INCOMPLETE = 2;
/** @removed
* @deprecated Replaced by {@link #DecodeException#SOURCE_MALFORMED_DATA}.
*/
- @java.lang.Deprecated
+ @Deprecated
public static final int ERROR_SOURCE_ERROR = 3;
/**
@@ -1000,7 +1000,7 @@
/** @removed
* @deprecated Renamed to {@link #setTargetSize}.
*/
- @java.lang.Deprecated
+ @Deprecated
public ImageDecoder setResize(int width, int height) {
this.setTargetSize(width, height);
return this;
@@ -1039,7 +1039,7 @@
/** @removed
* @deprecated Renamed to {@link #setTargetSampleSize}.
*/
- @java.lang.Deprecated
+ @Deprecated
public ImageDecoder setResize(int sampleSize) {
this.setTargetSampleSize(sampleSize);
return this;
@@ -1125,7 +1125,7 @@
/**
* Use a software allocation for the pixel memory.
*
- * Useful for drawing to a software {@link Canvas} or for
+ * <p>Useful for drawing to a software {@link Canvas} or for
* accessing the pixels on the final output.
*/
public static final int ALLOCATOR_SOFTWARE = 1;
@@ -1133,14 +1133,14 @@
/**
* Use shared memory for the pixel memory.
*
- * Useful for sharing across processes.
+ * <p>Useful for sharing across processes.
*/
public static final int ALLOCATOR_SHARED_MEMORY = 2;
/**
* Require a {@link Bitmap.Config#HARDWARE} {@link Bitmap}.
*
- * When this is combined with incompatible options, like
+ * <p>When this is combined with incompatible options, like
* {@link #setMutableRequired setMutableRequired(true)} or
* {@link #setDecodeAsAlphaMaskEnabled setDecodeAsAlphaMaskEnabled(true)},
* {@link #decodeDrawable decodeDrawable} or {@link #decodeBitmap decodeBitmap}
@@ -1203,7 +1203,7 @@
/** @removed
* @deprecated Renamed to {@link #setUnpremultipliedRequired}.
*/
- @java.lang.Deprecated
+ @Deprecated
public ImageDecoder setRequireUnpremultiplied(boolean unpremultipliedRequired) {
this.setUnpremultipliedRequired(unpremultipliedRequired);
return this;
@@ -1219,7 +1219,7 @@
/** @removed
* @deprecated Renamed to {@link #isUnpremultipliedRequired}.
*/
- @java.lang.Deprecated
+ @Deprecated
public boolean getRequireUnpremultiplied() {
return this.isUnpremultipliedRequired();
}
@@ -1348,7 +1348,7 @@
/** @removed
* @deprecated Renamed to {@link #setMutableRequired}.
*/
- @java.lang.Deprecated
+ @Deprecated
public ImageDecoder setMutable(boolean mutable) {
this.setMutableRequired(mutable);
return this;
@@ -1364,37 +1364,68 @@
/** @removed
* @deprecated Renamed to {@link #isMutableRequired}.
*/
- @java.lang.Deprecated
+ @Deprecated
public boolean getMutable() {
return this.isMutableRequired();
}
/**
- * Specify whether to potentially save RAM at the expense of quality.
+ * Save memory if possible by using a denser {@link Bitmap.Config} at the
+ * cost of some image quality.
*
- * <p>Setting this to {@code true} may result in a {@link Bitmap} with a
- * denser {@link Bitmap.Config}, depending on the image. For example, an
- * opaque {@link Bitmap} with 8 bits or precision for each of its red,
- * green and blue components would decode to
- * {@link Bitmap.Config#ARGB_8888} by default, but setting this to
- * {@code true} will result in decoding to {@link Bitmap.Config#RGB_565}.
- * This necessarily lowers the quality of the output, but saves half
- * the memory used.</p>
+ * <p>For example an opaque 8-bit image may be compressed into an
+ * {@link Bitmap.Config#RGB_565} configuration, sacrificing image
+ * quality to save memory.
+ */
+ public static final int MEMORY_POLICY_LOW_RAM = 0;
+
+ /**
+ * Use the most natural {@link Bitmap.Config} for the internal {@link Bitmap}.
+ *
+ * <p>This is the recommended default for most applications and usages. This
+ * will use the closest {@link Bitmap.Config} for the encoded source. If the
+ * encoded source does not exactly match any {@link Bitmap.Config}, the next
+ * highest quality {@link Bitmap.Config} will be used avoiding any loss in
+ * image quality.
+ */
+ public static final int MEMORY_POLICY_DEFAULT = 1;
+
+ /** @hide **/
+ @Retention(SOURCE)
+ @IntDef(value = { MEMORY_POLICY_DEFAULT, MEMORY_POLICY_LOW_RAM },
+ prefix = {"MEMORY_POLICY_"})
+ public @interface MemoryPolicy {};
+
+ /**
+ * Specify the memory policy for the decoded {@link Bitmap}.
*
* <p>Like all setters on ImageDecoder, this must be called inside
* {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
*/
+ public void setMemorySizePolicy(@MemoryPolicy int policy) {
+ mConserveMemory = (policy == MEMORY_POLICY_LOW_RAM);
+ }
+
+ /**
+ * Retrieve the memory policy for the decoded {@link Bitmap}.
+ */
+ @MemoryPolicy
+ public int getMemorySizePolicy() {
+ return mConserveMemory ? MEMORY_POLICY_LOW_RAM : MEMORY_POLICY_DEFAULT;
+ }
+
+ /** @removed
+ * @deprecated Replaced by {@link #setMemorySizePolicy}.
+ */
+ @Deprecated
public void setConserveMemory(boolean conserveMemory) {
mConserveMemory = conserveMemory;
}
- /**
- * Return whether this object will try to save RAM at the expense of quality.
- *
- * <p>This returns whether {@link #setConserveMemory} was set to {@code true}.
- * It may still return {@code true} even if the {@code ImageDecoder} does not
- * have a way to save RAM at the expense of quality for this image.</p>
+ /** @removed
+ * @deprecated Replaced by {@link #getMemorySizePolicy}.
*/
+ @Deprecated
public boolean getConserveMemory() {
return mConserveMemory;
}
@@ -1421,7 +1452,7 @@
/** @removed
* @deprecated Renamed to {@link #setDecodeAsAlphaMaskEnabled}.
*/
- @java.lang.Deprecated
+ @Deprecated
public ImageDecoder setDecodeAsAlphaMask(boolean enabled) {
this.setDecodeAsAlphaMaskEnabled(enabled);
return this;
@@ -1430,7 +1461,7 @@
/** @removed
* @deprecated Renamed to {@link #setDecodeAsAlphaMaskEnabled}.
*/
- @java.lang.Deprecated
+ @Deprecated
public ImageDecoder setAsAlphaMask(boolean asAlphaMask) {
this.setDecodeAsAlphaMask(asAlphaMask);
return this;
@@ -1451,7 +1482,7 @@
/** @removed
* @deprecated Renamed to {@link #isDecodeAsAlphaMaskEnabled}.
*/
- @java.lang.Deprecated
+ @Deprecated
public boolean getDecodeAsAlphaMask() {
return mDecodeAsAlphaMask;
}
@@ -1459,7 +1490,7 @@
/** @removed
* @deprecated Renamed to {@link #isDecodeAsAlphaMaskEnabled}.
*/
- @java.lang.Deprecated
+ @Deprecated
public boolean getAsAlphaMask() {
return this.getDecodeAsAlphaMask();
}
diff --git a/libs/protoutil/Android.bp b/libs/protoutil/Android.bp
index 4f1d2d5..7ad83ca 100644
--- a/libs/protoutil/Android.bp
+++ b/libs/protoutil/Android.bp
@@ -37,3 +37,20 @@
"liblog",
],
}
+
+cc_test {
+ name: "libprotoutil_test",
+
+ srcs: [
+ "tests/EncodedBuffer_test.cpp",
+ ],
+
+ shared_libs: [
+ "libcutils",
+ "libprotoutil",
+ ],
+
+ static_libs: [
+ "libgmock",
+ ],
+}
diff --git a/libs/protoutil/AndroidTest.xml b/libs/protoutil/AndroidTest.xml
new file mode 100644
index 0000000..46d418e
--- /dev/null
+++ b/libs/protoutil/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for libprotoutil_test">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="libprotoutil_test->/data/nativetest/libprotoutil_test" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/nativetest" />
+ <option name="module-name" value="libprotoutil_test" />
+ </test>
+</configuration>
diff --git a/libs/protoutil/src/EncodedBuffer.cpp b/libs/protoutil/src/EncodedBuffer.cpp
index 3a5e2e9..c017851 100644
--- a/libs/protoutil/src/EncodedBuffer.cpp
+++ b/libs/protoutil/src/EncodedBuffer.cpp
@@ -13,11 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#define LOG_TAG "libprotoutil"
+
+#include <stdlib.h>
#include <android/util/EncodedBuffer.h>
#include <android/util/protobuf.h>
-
-#include <stdlib.h>
+#include <cutils/log.h>
namespace android {
namespace util {
@@ -228,7 +230,7 @@
size_t start = mEp.pos();
while (true) {
uint8_t byte = readRawByte();
- val += (byte & 0x7F) << shift;
+ val |= (UINT64_C(0x7F) & byte) << shift;
if ((byte & 0x80) == 0) break;
shift += 7;
}
@@ -345,7 +347,7 @@
uint64_t val = 0, shift = 0;
while (true) {
uint8_t byte = next();
- val += (byte & 0x7F) << shift;
+ val |= (INT64_C(0x7F) & byte) << shift;
if ((byte & 0x80) == 0) break;
shift += 7;
}
diff --git a/libs/protoutil/tests/EncodedBuffer_test.cpp b/libs/protoutil/tests/EncodedBuffer_test.cpp
new file mode 100644
index 0000000..615ab4a
--- /dev/null
+++ b/libs/protoutil/tests/EncodedBuffer_test.cpp
@@ -0,0 +1,25 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include <android/util/EncodedBuffer.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace android::util;
+
+TEST(EncodedBufferTest, ReadVarint) {
+ EncodedBuffer buffer;
+ uint64_t val = UINT64_C(1522865904593);
+ buffer.writeRawVarint64(val);
+ EXPECT_EQ(val, buffer.begin().readRawVarint());
+}
diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java
index 21d6873..1cb4d67 100644
--- a/media/java/android/media/audiofx/AudioEffect.java
+++ b/media/java/android/media/audiofx/AudioEffect.java
@@ -18,6 +18,7 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.TestApi;
import android.app.ActivityThread;
import android.os.Handler;
import android.os.Looper;
@@ -133,9 +134,10 @@
.fromString("7261676f-6d75-7369-6364-28e2fd3ac39e");
/**
- * Null effect UUID. Used when the UUID for effect type of
+ * Null effect UUID. See {@link AudioEffect(UUID, UUID, int, int)} for use.
* @hide
*/
+ @TestApi
public static final UUID EFFECT_TYPE_NULL = UUID
.fromString("ec7178ec-e5e1-4432-a3f4-4657e6795210");
diff --git a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
index 3577c0f..c238e54 100644
--- a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
@@ -18,8 +18,8 @@
import android.content.Context;
import android.content.pm.PackageManager;
-import android.hardware.biometrics.BiometricDialog;
-import android.hardware.biometrics.IBiometricDialogReceiver;
+import android.hardware.biometrics.BiometricPrompt;
+import android.hardware.biometrics.IBiometricPromptReceiver;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -48,7 +48,7 @@
private FingerprintDialogView mDialogView;
private WindowManager mWindowManager;
- private IBiometricDialogReceiver mReceiver;
+ private IBiometricPromptReceiver mReceiver;
private boolean mDialogShowing;
private Handler mHandler = new Handler() {
@@ -97,7 +97,7 @@
}
@Override
- public void showFingerprintDialog(Bundle bundle, IBiometricDialogReceiver receiver) {
+ public void showFingerprintDialog(Bundle bundle, IBiometricPromptReceiver receiver) {
if (DEBUG) Log.d(TAG, "showFingerprintDialog");
// Remove these messages as they are part of the previous client
mHandler.removeMessages(MSG_FINGERPRINT_ERROR);
@@ -139,7 +139,7 @@
Log.w(TAG, "Dialog already showing");
return;
}
- mReceiver = (IBiometricDialogReceiver) args.arg2;
+ mReceiver = (IBiometricPromptReceiver) args.arg2;
mDialogView.setBundle((Bundle)args.arg1);
mWindowManager.addView(mDialogView, mDialogView.getLayoutParams());
mDialogShowing = true;
@@ -177,7 +177,7 @@
}
if (userCanceled) {
try {
- mReceiver.onDialogDismissed(BiometricDialog.DISMISSED_REASON_USER_CANCEL);
+ mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException when hiding dialog", e);
}
@@ -193,7 +193,7 @@
return;
}
try {
- mReceiver.onDialogDismissed(BiometricDialog.DISMISSED_REASON_NEGATIVE);
+ mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_NEGATIVE);
} catch (RemoteException e) {
Log.e(TAG, "Remote exception when handling negative button", e);
}
@@ -206,7 +206,7 @@
return;
}
try {
- mReceiver.onDialogDismissed(BiometricDialog.DISMISSED_REASON_POSITIVE);
+ mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_POSITIVE);
} catch (RemoteException e) {
Log.e(TAG, "Remote exception when handling positive button", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
index 3e1ac02..6921836 100644
--- a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
@@ -22,7 +22,7 @@
import android.graphics.PorterDuff;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
-import android.hardware.biometrics.BiometricDialog;
+import android.hardware.biometrics.BiometricPrompt;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -161,10 +161,10 @@
mLastState = STATE_NONE;
updateFingerprintIcon(STATE_FINGERPRINT);
- title.setText(mBundle.getCharSequence(BiometricDialog.KEY_TITLE));
+ title.setText(mBundle.getCharSequence(BiometricPrompt.KEY_TITLE));
title.setSelected(true);
- final CharSequence subtitleText = mBundle.getCharSequence(BiometricDialog.KEY_SUBTITLE);
+ final CharSequence subtitleText = mBundle.getCharSequence(BiometricPrompt.KEY_SUBTITLE);
if (subtitleText == null) {
subtitle.setVisibility(View.GONE);
} else {
@@ -172,18 +172,18 @@
subtitle.setText(subtitleText);
}
- final CharSequence descriptionText = mBundle.getCharSequence(BiometricDialog.KEY_DESCRIPTION);
+ final CharSequence descriptionText = mBundle.getCharSequence(BiometricPrompt.KEY_DESCRIPTION);
if (descriptionText == null) {
subtitle.setVisibility(View.VISIBLE);
description.setVisibility(View.GONE);
} else {
- description.setText(mBundle.getCharSequence(BiometricDialog.KEY_DESCRIPTION));
+ description.setText(mBundle.getCharSequence(BiometricPrompt.KEY_DESCRIPTION));
}
- negative.setText(mBundle.getCharSequence(BiometricDialog.KEY_NEGATIVE_TEXT));
+ negative.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT));
final CharSequence positiveText =
- mBundle.getCharSequence(BiometricDialog.KEY_POSITIVE_TEXT);
+ mBundle.getCharSequence(BiometricPrompt.KEY_POSITIVE_TEXT);
positive.setText(positiveText); // needs to be set for marquee to work
if (positiveText != null) {
positive.setVisibility(View.VISIBLE);
@@ -269,7 +269,7 @@
mErrorText.setTextColor(mErrorColor);
mErrorText.setContentDescription(message);
mHandler.sendMessageDelayed(mHandler.obtainMessage(FingerprintDialogImpl.MSG_CLEAR_MESSAGE),
- BiometricDialog.HIDE_DIALOG_DELAY);
+ BiometricPrompt.HIDE_DIALOG_DELAY);
}
public void showHelpMessage(String message) {
@@ -279,7 +279,7 @@
public void showErrorMessage(String error) {
showTemporaryMessage(error);
mHandler.sendMessageDelayed(mHandler.obtainMessage(FingerprintDialogImpl.MSG_HIDE_DIALOG,
- false /* userCanceled */), BiometricDialog.HIDE_DIALOG_DELAY);
+ false /* userCanceled */), BiometricPrompt.HIDE_DIALOG_DELAY);
}
private void updateFingerprintIcon(int newState) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 65037f9..6fd0aa6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -18,7 +18,7 @@
import android.content.ComponentName;
import android.graphics.Rect;
-import android.hardware.biometrics.IBiometricDialogReceiver;
+import android.hardware.biometrics.IBiometricPromptReceiver;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -160,7 +160,7 @@
default void onRotationProposal(int rotation, boolean isValid) { }
- default void showFingerprintDialog(Bundle bundle, IBiometricDialogReceiver receiver) { }
+ default void showFingerprintDialog(Bundle bundle, IBiometricPromptReceiver receiver) { }
default void onFingerprintAuthenticated() { }
default void onFingerprintHelp(String message) { }
default void onFingerprintError(String error) { }
@@ -513,7 +513,7 @@
}
@Override
- public void showFingerprintDialog(Bundle bundle, IBiometricDialogReceiver receiver) {
+ public void showFingerprintDialog(Bundle bundle, IBiometricPromptReceiver receiver) {
synchronized (mLock) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = bundle;
@@ -759,7 +759,7 @@
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).showFingerprintDialog(
(Bundle)((SomeArgs)msg.obj).arg1,
- (IBiometricDialogReceiver)((SomeArgs)msg.obj).arg2);
+ (IBiometricPromptReceiver)((SomeArgs)msg.obj).arg2);
}
break;
case MSG_FINGERPRINT_AUTHENTICATED:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 4c4eb60..db2139d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -39,7 +39,6 @@
import android.os.Handler;
import android.os.Message;
import android.os.SystemProperties;
-import android.os.VibrationEffect;
import android.support.annotation.ColorInt;
import android.util.AttributeSet;
import android.util.Log;
@@ -69,7 +68,6 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.NavigationBarCompat;
import com.android.systemui.stackdivider.Divider;
-import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.policy.DeadZone;
import com.android.systemui.statusbar.policy.KeyButtonDrawable;
import com.android.systemui.statusbar.policy.TintedKeyButtonDrawable;
@@ -150,7 +148,6 @@
private Divider mDivider;
private RecentsOnboarding mRecentsOnboarding;
private NotificationPanelView mPanelView;
- private final VibratorHelper mVibratorHelper;
private int mRotateBtnStyle = R.style.RotateButtonCCWStart90;
@@ -246,7 +243,6 @@
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
- mVibratorHelper = Dependency.get(VibratorHelper.class);
mConfiguration = new Configuration();
mConfiguration.updateFrom(context.getResources().getConfiguration());
@@ -314,9 +310,6 @@
} else if (mRecentsButtonBounds.contains(x, y)) {
mDownHitTarget = HIT_TARGET_OVERVIEW;
}
-
- // Vibrate tick whenever down occurs on navigation bar
- mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
break;
}
return mGestureHelper.onInterceptTouchEvent(event);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 2d2d708..3dbac51 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -395,7 +395,7 @@
// Darken scrim as you pull down the shade when unlocked
float behindFraction = getInterpolatedFraction();
behindFraction = (float) Math.pow(behindFraction, 0.8f);
- mCurrentBehindAlpha = behindFraction * mScrimBehindAlphaKeyguard;
+ mCurrentBehindAlpha = behindFraction * GRADIENT_SCRIM_ALPHA_BUSY;
mCurrentInFrontAlpha = 0;
} else if (mState == ScrimState.KEYGUARD) {
// Either darken of make the scrim transparent when you
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 2fed3fc..1b02e15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -28,7 +28,6 @@
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
-import android.os.VibrationEffect;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.HapticFeedbackConstants;
@@ -50,7 +49,6 @@
import com.android.systemui.R;
import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider.ButtonInterface;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.statusbar.VibratorHelper;
import static android.view.KeyEvent.KEYCODE_HOME;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
@@ -75,7 +73,6 @@
private OnClickListener mOnClickListener;
private final KeyButtonRipple mRipple;
private final OverviewProxyService mOverviewProxyService;
- private final VibratorHelper mVibratorHelper;
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
private final Runnable mCheckLongPress = new Runnable() {
@@ -121,7 +118,6 @@
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mRipple = new KeyButtonRipple(context, this);
- mVibratorHelper = Dependency.get(VibratorHelper.class);
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
setBackground(mRipple);
}
@@ -262,9 +258,8 @@
final boolean doHapticFeedback = (SystemClock.uptimeMillis() - mDownTime) > 150;
if (showSwipeUI) {
if (doIt) {
- if (doHapticFeedback) {
- mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
- }
+ // Apply haptic feedback on touch up since there is none on touch down
+ performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
playSoundEffect(SoundEffectConstants.CLICK);
}
} else if (doHapticFeedback && !mLongClicked) {
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index 2ac389d..d1808d8 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -32,6 +32,9 @@
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+
+import android.Manifest;
import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.app.KeyguardManager;
@@ -41,6 +44,7 @@
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.os.Binder;
@@ -51,6 +55,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.HarmfulAppWarningActivity;
+import com.android.internal.app.SuspendedAppActivity;
import com.android.internal.app.UnlaunchableAppActivity;
import com.android.server.LocalServices;
@@ -151,7 +156,7 @@
mInTask = inTask;
mActivityOptions = activityOptions;
- if (interceptSuspendPackageIfNeed()) {
+ if (interceptSuspendedPackageIfNeeded()) {
// Skip the rest of interceptions as the package is suspended by device admin so
// no user action can undo this.
return true;
@@ -204,12 +209,7 @@
return true;
}
- private boolean interceptSuspendPackageIfNeed() {
- // Do not intercept if the admin did not suspend the package
- if (mAInfo == null || mAInfo.applicationInfo == null ||
- (mAInfo.applicationInfo.flags & FLAG_SUSPENDED) == 0) {
- return false;
- }
+ private boolean interceptSuspendedByAdminPackage() {
DevicePolicyManagerInternal devicePolicyManager = LocalServices
.getService(DevicePolicyManagerInternal.class);
if (devicePolicyManager == null) {
@@ -232,6 +232,55 @@
return true;
}
+ private Intent createSuspendedAppInterceptIntent(String suspendedPackage,
+ String suspendingPackage, String dialogMessage, int userId) {
+ final Intent interceptIntent = new Intent(mServiceContext, SuspendedAppActivity.class)
+ .putExtra(Intent.EXTRA_PACKAGE_NAME, suspendedPackage)
+ .putExtra(SuspendedAppActivity.EXTRA_DIALOG_MESSAGE, dialogMessage)
+ .putExtra(Intent.EXTRA_USER_ID, userId)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+
+ final Intent moreDetailsIntent = new Intent(Intent.ACTION_SHOW_SUSPENDED_APP_DETAILS)
+ .setPackage(suspendingPackage);
+ final String requiredPermission = Manifest.permission.SEND_SHOW_SUSPENDED_APP_DETAILS;
+ final ResolveInfo resolvedInfo = mSupervisor.resolveIntent(moreDetailsIntent, null, userId);
+ if (resolvedInfo != null && resolvedInfo.activityInfo != null
+ && requiredPermission.equals(resolvedInfo.activityInfo.permission)) {
+ moreDetailsIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, suspendedPackage)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ interceptIntent.putExtra(SuspendedAppActivity.EXTRA_MORE_DETAILS_INTENT,
+ moreDetailsIntent);
+ }
+ return interceptIntent;
+ }
+
+ private boolean interceptSuspendedPackageIfNeeded() {
+ // Do not intercept if the package is not suspended
+ if (mAInfo == null || mAInfo.applicationInfo == null ||
+ (mAInfo.applicationInfo.flags & FLAG_SUSPENDED) == 0) {
+ return false;
+ }
+ final PackageManagerInternal pmi = mService.getPackageManagerInternalLocked();
+ if (pmi == null) {
+ return false;
+ }
+ final String suspendedPackage = mAInfo.applicationInfo.packageName;
+ final String suspendingPackage = pmi.getSuspendingPackage(suspendedPackage, mUserId);
+ if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
+ return interceptSuspendedByAdminPackage();
+ }
+ final String dialogMessage = pmi.getSuspendedDialogMessage(suspendedPackage, mUserId);
+ mIntent = createSuspendedAppInterceptIntent(suspendedPackage, suspendingPackage,
+ dialogMessage, mUserId);
+ mCallingPid = mRealCallingPid;
+ mCallingUid = mRealCallingUid;
+ mResolvedType = null;
+ mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, 0);
+ mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
+ return true;
+ }
+
private boolean interceptWorkProfileChallengeIfNeeded() {
final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(mAInfo, mUserId);
if (interceptingIntent == null) {
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 8faf931..5337566 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -28,6 +28,7 @@
import static android.app.ActivityManager.START_TASK_TO_FRONT;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -902,14 +903,22 @@
final int clearTaskFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK;
boolean clearedTask = (mLaunchFlags & clearTaskFlags) == clearTaskFlags
&& mReuseTask != null;
- if (startedActivityStack.inPinnedWindowingMode()
- && (result == START_TASK_TO_FRONT || result == START_DELIVERED_TO_TOP
- || clearedTask)) {
- // The activity was already running in the pinned stack so it wasn't started, but either
- // brought to the front or the new intent was delivered to it since it was already in
- // front. Notify anyone interested in this piece of information.
- mService.mTaskChangeNotificationController.notifyPinnedActivityRestartAttempt(
- clearedTask);
+ if (result == START_TASK_TO_FRONT || result == START_DELIVERED_TO_TOP || clearedTask) {
+ // The activity was already running so it wasn't started, but either brought to the
+ // front or the new intent was delivered to it since it was already in front. Notify
+ // anyone interested in this piece of information.
+ switch (startedActivityStack.getWindowingMode()) {
+ case WINDOWING_MODE_PINNED:
+ mService.mTaskChangeNotificationController.notifyPinnedActivityRestartAttempt(
+ clearedTask);
+ break;
+ case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
+ final ActivityStack homeStack = mSupervisor.mHomeStack;
+ if (homeStack != null && homeStack.shouldBeVisible(null /* starting */)) {
+ mService.mWindowManager.showRecentApps();
+ }
+ break;
+ }
}
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 5ca9abc..b9a279a 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -436,6 +436,10 @@
com.android.internal.R.bool.config_localDisplaysMirrorContent)) {
mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
}
+
+ if (res.getBoolean(com.android.internal.R.bool.config_localDisplaysPrivate)) {
+ mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE;
+ }
}
}
return mInfo;
diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
index 8be2c9e..afd1a94 100644
--- a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
+++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
@@ -18,8 +18,8 @@
import android.content.Context;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
-import android.hardware.biometrics.BiometricDialog;
-import android.hardware.biometrics.IBiometricDialogReceiver;
+import android.hardware.biometrics.BiometricPrompt;
+import android.hardware.biometrics.IBiometricPromptReceiver;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
@@ -46,8 +46,8 @@
public static final int LOCKOUT_PERMANENT = 2;
// Callback mechanism received from the client
- // (BiometricDialog -> FingerprintManager -> FingerprintService -> AuthenticationClient)
- private IBiometricDialogReceiver mDialogReceiverFromClient;
+ // (BiometricPrompt -> FingerprintManager -> FingerprintService -> AuthenticationClient)
+ private IBiometricPromptReceiver mDialogReceiverFromClient;
private Bundle mBundle;
private IStatusBarService mStatusBarService;
private boolean mInLockout;
@@ -55,13 +55,13 @@
protected boolean mDialogDismissed;
// Receives events from SystemUI and handles them before forwarding them to FingerprintDialog
- protected IBiometricDialogReceiver mDialogReceiver = new IBiometricDialogReceiver.Stub() {
+ protected IBiometricPromptReceiver mDialogReceiver = new IBiometricPromptReceiver.Stub() {
@Override // binder call
public void onDialogDismissed(int reason) {
if (mBundle != null && mDialogReceiverFromClient != null) {
try {
mDialogReceiverFromClient.onDialogDismissed(reason);
- if (reason == BiometricDialog.DISMISSED_REASON_USER_CANCEL) {
+ if (reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL) {
onError(FingerprintManager.FINGERPRINT_ERROR_USER_CANCELED,
0 /* vendorCode */);
}
@@ -88,7 +88,7 @@
public AuthenticationClient(Context context, long halDeviceId, IBinder token,
IFingerprintServiceReceiver receiver, int targetUserId, int groupId, long opId,
boolean restricted, String owner, Bundle bundle,
- IBiometricDialogReceiver dialogReceiver, IStatusBarService statusBarService) {
+ IBiometricPromptReceiver dialogReceiver, IStatusBarService statusBarService) {
super(context, halDeviceId, token, receiver, targetUserId, groupId, restricted, owner);
mOpId = opId;
mBundle = bundle;
@@ -299,7 +299,7 @@
// If the user already cancelled authentication (via some interaction with the
// dialog, we do not need to hide it since it's already hidden.
// If the device is in lockout, don't hide the dialog - it will automatically hide
- // after BiometricDialog.HIDE_DIALOG_DELAY
+ // after BiometricPrompt.HIDE_DIALOG_DELAY
if (mBundle != null && !mDialogDismissed && !mInLockout) {
try {
mStatusBarService.hideFingerprintDialog();
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 92d3772..4e95bdf 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -38,7 +38,7 @@
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
-import android.hardware.biometrics.IBiometricDialogReceiver;
+import android.hardware.biometrics.IBiometricPromptReceiver;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprintClientCallback;
import android.hardware.fingerprint.Fingerprint;
@@ -849,7 +849,7 @@
private void startAuthentication(IBinder token, long opId, int callingUserId, int groupId,
IFingerprintServiceReceiver receiver, int flags, boolean restricted,
- String opPackageName, Bundle bundle, IBiometricDialogReceiver dialogReceiver) {
+ String opPackageName, Bundle bundle, IBiometricPromptReceiver dialogReceiver) {
updateActiveGroup(groupId, opPackageName);
if (DEBUG) Slog.v(TAG, "startAuthentication(" + opPackageName + ")");
@@ -1160,7 +1160,7 @@
public void authenticate(final IBinder token, final long opId, final int groupId,
final IFingerprintServiceReceiver receiver, final int flags,
final String opPackageName, final Bundle bundle,
- final IBiometricDialogReceiver dialogReceiver) {
+ final IBiometricPromptReceiver dialogReceiver) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final int callingUserId = UserHandle.getCallingUserId();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 33c7681..26d4037 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -274,6 +274,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IMediaContainerService;
import com.android.internal.app.ResolverActivity;
+import com.android.internal.app.SuspendedAppActivity;
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.PackageHelper;
import com.android.internal.logging.MetricsLogger;
@@ -14006,8 +14007,8 @@
@Override
public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
- PersistableBundle appExtras, PersistableBundle launcherExtras, String callingPackage,
- int userId) {
+ PersistableBundle appExtras, PersistableBundle launcherExtras, String dialogMessage,
+ String callingPackage, int userId) {
try {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS, null);
} catch (SecurityException e) {
@@ -14055,7 +14056,7 @@
unactionedPackages.add(packageName);
continue;
}
- pkgSetting.setSuspended(suspended, callingPackage, appExtras,
+ pkgSetting.setSuspended(suspended, callingPackage, dialogMessage, appExtras,
launcherExtras, userId);
changedPackagesList.add(packageName);
}
@@ -14177,7 +14178,7 @@
for (int user : userIds) {
final PackageUserState pus = ps.readUserState(user);
if (pus.suspended && packageName.equals(pus.suspendingPackage)) {
- ps.setSuspended(false, null, null, null, user);
+ ps.setSuspended(false, null, null, null, null, user);
}
}
}
@@ -18911,6 +18912,7 @@
false /*hidden*/,
false /*suspended*/,
null, /*suspendingPackage*/
+ null, /*dialogMessage*/
null, /*suspendedAppExtras*/
null, /*suspendedLauncherExtras*/
false /*instantApp*/,
@@ -23803,6 +23805,22 @@
}
@Override
+ public String getSuspendingPackage(String suspendedPackage, int userId) {
+ synchronized (mPackages) {
+ final PackageSetting ps = mSettings.mPackages.get(suspendedPackage);
+ return (ps != null) ? ps.readUserState(userId).suspendingPackage : null;
+ }
+ }
+
+ @Override
+ public String getSuspendedDialogMessage(String suspendedPackage, int userId) {
+ synchronized (mPackages) {
+ final PackageSetting ps = mSettings.mPackages.get(suspendedPackage);
+ return (ps != null) ? ps.readUserState(userId).dialogMessage : null;
+ }
+ }
+
+ @Override
public int getPackageUid(String packageName, int flags, int userId) {
return PackageManagerService.this
.getPackageUid(packageName, flags, userId);
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 28e32a5..a92fbb6 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1505,6 +1505,7 @@
private int runSuspend(boolean suspendedState) {
final PrintWriter pw = getOutPrintWriter();
int userId = UserHandle.USER_SYSTEM;
+ String dialogMessage = null;
final PersistableBundle appExtras = new PersistableBundle();
final PersistableBundle launcherExtras = new PersistableBundle();
String opt;
@@ -1513,6 +1514,9 @@
case "--user":
userId = UserHandle.parseUserArg(getNextArgRequired());
break;
+ case "--dialogMessage":
+ dialogMessage = getNextArgRequired();
+ break;
case "--ael":
case "--aes":
case "--aed":
@@ -1553,7 +1557,7 @@
(Binder.getCallingUid() == Process.ROOT_UID) ? "root" : "com.android.shell";
try {
mInterface.setPackagesSuspendedAsUser(new String[]{packageName}, suspendedState,
- appExtras, launcherExtras, callingPackage, userId);
+ appExtras, launcherExtras, dialogMessage, callingPackage, userId);
pw.println("Package " + packageName + " new suspended state: "
+ mInterface.isPackageSuspendedForUser(packageName, userId));
return 0;
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 008a81c..fd4c5e9 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -398,11 +398,12 @@
return readUserState(userId).suspended;
}
- void setSuspended(boolean suspended, String suspendingPackage, PersistableBundle appExtras,
- PersistableBundle launcherExtras, int userId) {
+ void setSuspended(boolean suspended, String suspendingPackage, String dialogMessage,
+ PersistableBundle appExtras, PersistableBundle launcherExtras, int userId) {
final PackageUserState existingUserState = modifyUserState(userId);
existingUserState.suspended = suspended;
existingUserState.suspendingPackage = suspended ? suspendingPackage : null;
+ existingUserState.dialogMessage = suspended ? dialogMessage : null;
existingUserState.suspendedAppExtras = suspended ? appExtras : null;
existingUserState.suspendedLauncherExtras = suspended ? launcherExtras : null;
}
@@ -425,8 +426,8 @@
void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped,
boolean notLaunched, boolean hidden, boolean suspended, String suspendingPackage,
- PersistableBundle suspendedAppExtras, PersistableBundle suspendedLauncherExtras,
- boolean instantApp,
+ String dialogMessage, PersistableBundle suspendedAppExtras,
+ PersistableBundle suspendedLauncherExtras, boolean instantApp,
boolean virtualPreload, String lastDisableAppCaller,
ArraySet<String> enabledComponents, ArraySet<String> disabledComponents,
int domainVerifState, int linkGeneration, int installReason,
@@ -440,6 +441,7 @@
state.hidden = hidden;
state.suspended = suspended;
state.suspendingPackage = suspendingPackage;
+ state.dialogMessage = dialogMessage;
state.suspendedAppExtras = suspendedAppExtras;
state.suspendedLauncherExtras = suspendedLauncherExtras;
state.lastDisableAppCaller = lastDisableAppCaller;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index d0e8544..898ecf3 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -222,6 +222,7 @@
private static final String ATTR_HIDDEN = "hidden";
private static final String ATTR_SUSPENDED = "suspended";
private static final String ATTR_SUSPENDING_PACKAGE = "suspending-package";
+ private static final String ATTR_SUSPEND_DIALOG_MESSAGE = "suspend_dialog_message";
// Legacy, uninstall blocks are stored separately.
@Deprecated
private static final String ATTR_BLOCK_UNINSTALL = "blockUninstall";
@@ -734,6 +735,7 @@
false /*hidden*/,
false /*suspended*/,
null, /*suspendingPackage*/
+ null, /*dialogMessage*/
null, /*suspendedAppExtras*/
null, /*suspendedLauncherExtras*/
instantApp,
@@ -1628,6 +1630,7 @@
false /*hidden*/,
false /*suspended*/,
null, /*suspendingPackage*/
+ null, /*dialogMessage*/
null, /*suspendedAppExtras*/
null, /*suspendedLauncherExtras*/
false /*instantApp*/,
@@ -1704,6 +1707,8 @@
false);
String suspendingPackage = parser.getAttributeValue(null,
ATTR_SUSPENDING_PACKAGE);
+ final String dialogMessage = parser.getAttributeValue(null,
+ ATTR_SUSPEND_DIALOG_MESSAGE);
if (suspended && suspendingPackage == null) {
suspendingPackage = PLATFORM_PACKAGE_NAME;
}
@@ -1767,7 +1772,7 @@
setBlockUninstallLPw(userId, name, true);
}
ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched,
- hidden, suspended, suspendingPackage, suspendedAppExtras,
+ hidden, suspended, suspendingPackage, dialogMessage, suspendedAppExtras,
suspendedLauncherExtras, instantApp, virtualPreload, enabledCaller,
enabledComponents, disabledComponents, verifState, linkGeneration,
installReason, harmfulAppWarning);
@@ -2077,7 +2082,14 @@
}
if (ustate.suspended) {
serializer.attribute(null, ATTR_SUSPENDED, "true");
- serializer.attribute(null, ATTR_SUSPENDING_PACKAGE, ustate.suspendingPackage);
+ if (ustate.suspendingPackage != null) {
+ serializer.attribute(null, ATTR_SUSPENDING_PACKAGE,
+ ustate.suspendingPackage);
+ }
+ if (ustate.dialogMessage != null) {
+ serializer.attribute(null, ATTR_SUSPEND_DIALOG_MESSAGE,
+ ustate.dialogMessage);
+ }
if (ustate.suspendedAppExtras != null) {
serializer.startTag(null, TAG_SUSPENDED_APP_EXTRAS);
try {
@@ -4750,8 +4762,11 @@
pw.print(" suspended=");
pw.print(ps.getSuspended(user.id));
if (ps.getSuspended(user.id)) {
+ final PackageUserState pus = ps.readUserState(user.id);
pw.print(" suspendingPackage=");
- pw.print(ps.readUserState(user.id).suspendingPackage);
+ pw.print(pus.suspendingPackage);
+ pw.print(" dialogMessage=");
+ pw.print(pus.dialogMessage);
}
pw.print(" stopped=");
pw.print(ps.getStopped(user.id));
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 8af1101..2db8039 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -23,7 +23,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Rect;
-import android.hardware.biometrics.IBiometricDialogReceiver;
+import android.hardware.biometrics.IBiometricPromptReceiver;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -547,7 +547,7 @@
}
@Override
- public void showFingerprintDialog(Bundle bundle, IBiometricDialogReceiver receiver) {
+ public void showFingerprintDialog(Bundle bundle, IBiometricPromptReceiver receiver) {
if (mBar != null) {
try {
mBar.showFingerprintDialog(bundle, receiver);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 36dc121..9bc5fca 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -9193,7 +9193,7 @@
long id = mInjector.binderClearCallingIdentity();
try {
return mIPackageManager.setPackagesSuspendedAsUser(
- packageNames, suspended, null, null, "android", callingUserId);
+ packageNames, suspended, null, null, null, "android", callingUserId);
} catch (RemoteException re) {
// Shouldn't happen.
Slog.e(LOG_TAG, "Failed talking to the package manager", re);
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index cdb339a..a85f21c 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -29,6 +29,7 @@
truth-prebuilt \
testables \
testng \
+ ub-uiautomator\
platformprotosnano
LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl
@@ -69,8 +70,6 @@
LOCAL_JACK_FLAGS := --multi-dex native
LOCAL_DX_FLAGS := --multi-dex
-LOCAL_STATIC_JAVA_LIBRARIES += ub-uiautomator
-
LOCAL_PROGUARD_ENABLED := disabled
include $(BUILD_PACKAGE)
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index ce98d65..22bec44 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -63,6 +63,7 @@
<uses-permission android:name="android.permission.WATCH_APPOPS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.SUSPEND_APPS"/>
+ <uses-permission android:name="android.permission.CONTROL_KEYGUARD"/>
<!-- Uses API introduced in O (26) -->
<uses-sdk android:minSdkVersion="1"
@@ -145,6 +146,15 @@
<activity android:name="com.android.server.pm.ShortcutTestActivity"
android:enabled="true" android:exported="true" />
+ <activity android:name="com.android.server.pm.SuspendedDetailsActivity"
+ android:enabled="true"
+ android:permission="android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS">
+ <intent-filter>
+ <action android:name="android.intent.action.SHOW_SUSPENDED_APP_DETAILS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
<activity android:name="com.android.server.accounts.AccountAuthenticatorDummyActivity" />
<activity-alias android:name="a.ShortcutEnabled"
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java
index f76eb56..477558a 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java
@@ -17,6 +17,9 @@
package com.android.server.am;
import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
+
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -30,6 +33,7 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
@@ -79,6 +83,8 @@
@Mock
private DevicePolicyManagerInternal mDevicePolicyManager;
@Mock
+ private PackageManagerInternal mPackageManagerInternal;
+ @Mock
private UserManager mUserManager;
@Mock
private UserController mUserController;
@@ -103,6 +109,7 @@
when(mDevicePolicyManager
.createShowAdminSupportIntent(TEST_USER_ID, true))
.thenReturn(ADMIN_SUPPORT_INTENT);
+ when(mService.getPackageManagerInternalLocked()).thenReturn(mPackageManagerInternal);
// Mock UserManager
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
@@ -115,15 +122,18 @@
thenReturn(CONFIRM_CREDENTIALS_INTENT);
// Initialise activity info
- mAInfo.packageName = TEST_PACKAGE_NAME;
mAInfo.applicationInfo = new ApplicationInfo();
+ mAInfo.packageName = mAInfo.applicationInfo.packageName = TEST_PACKAGE_NAME;
}
@Test
- public void testSuspendedPackage() {
+ public void testSuspendedByAdminPackage() {
// GIVEN the package we're about to launch is currently suspended
mAInfo.applicationInfo.flags = FLAG_SUSPENDED;
+ when(mPackageManagerInternal.getSuspendingPackage(TEST_PACKAGE_NAME, TEST_USER_ID))
+ .thenReturn(PLATFORM_PACKAGE_NAME);
+
// THEN calling intercept returns true
assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index ebb4248..97ff94f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -199,13 +199,13 @@
PACKAGE_NAME_1, 1L, 0.01, true, "appString1");
final PersistableBundle launcherExtras1 = getPersistableBundle(
PACKAGE_NAME_1, 10L, 0.1, false, "launcherString1");
- ps1.setSuspended(true, "suspendingPackage1", appExtras1, launcherExtras1, 0);
+ ps1.setSuspended(true, "suspendingPackage1", "dialogMsg1", appExtras1, launcherExtras1, 0);
settingsUnderTest.mPackages.put(PACKAGE_NAME_1, ps1);
- ps2.setSuspended(true, "suspendingPackage2", null, null, 0);
+ ps2.setSuspended(true, "suspendingPackage2", "dialogMsg2", null, null, 0);
settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
- ps3.setSuspended(false, "irrelevant", null, null, 0);
+ ps3.setSuspended(false, "irrelevant", "irrevelant2", null, null, 0);
settingsUnderTest.mPackages.put(PACKAGE_NAME_3, ps3);
settingsUnderTest.writePackageRestrictionsLPr(0);
@@ -220,6 +220,7 @@
readUserState(0);
assertThat(readPus1.suspended, is(true));
assertThat(readPus1.suspendingPackage, equalTo("suspendingPackage1"));
+ assertThat(readPus1.dialogMessage, equalTo("dialogMsg1"));
assertThat(BaseBundle.kindofEquals(readPus1.suspendedAppExtras, appExtras1), is(true));
assertThat(BaseBundle.kindofEquals(readPus1.suspendedLauncherExtras, launcherExtras1),
is(true));
@@ -228,12 +229,17 @@
readUserState(0);
assertThat(readPus2.suspended, is(true));
assertThat(readPus2.suspendingPackage, equalTo("suspendingPackage2"));
+ assertThat(readPus2.dialogMessage, equalTo("dialogMsg2"));
assertThat(readPus2.suspendedAppExtras, is(nullValue()));
assertThat(readPus2.suspendedLauncherExtras, is(nullValue()));
final PackageUserState readPus3 = settingsUnderTest.mPackages.get(PACKAGE_NAME_3).
readUserState(0);
assertThat(readPus3.suspended, is(false));
+ assertThat(readPus3.suspendingPackage, is(nullValue()));
+ assertThat(readPus3.dialogMessage, is(nullValue()));
+ assertThat(readPus3.suspendedAppExtras, is(nullValue()));
+ assertThat(readPus3.suspendedLauncherExtras, is(nullValue()));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
index 4e1418c..2a4ea8c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
@@ -184,30 +184,40 @@
launcherExtras2.putString("name", "launcherExtras2");
final String suspendingPackage1 = "package1";
final String suspendingPackage2 = "package2";
+ final String dialogMessage1 = "dialogMessage1";
+ final String dialogMessage2 = "dialogMessage2";
final PackageUserState testUserState1 = new PackageUserState();
testUserState1.suspended = true;
testUserState1.suspendedAppExtras = appExtras1;
testUserState1.suspendedLauncherExtras = launcherExtras1;
testUserState1.suspendingPackage = suspendingPackage1;
+ testUserState1.dialogMessage = dialogMessage1;
- final PackageUserState testUserState2 = new PackageUserState(testUserState1);
+ PackageUserState testUserState2 = new PackageUserState(testUserState1);
assertThat(testUserState1.equals(testUserState2), is(true));
testUserState2.suspendingPackage = suspendingPackage2;
assertThat(testUserState1.equals(testUserState2), is(false));
- testUserState2.suspendingPackage = testUserState1.suspendingPackage;
+ testUserState2 = new PackageUserState(testUserState1);
testUserState2.suspendedAppExtras = appExtras2;
assertThat(testUserState1.equals(testUserState2), is(false));
- testUserState2.suspendedAppExtras = testUserState1.suspendedAppExtras;
+ testUserState2 = new PackageUserState(testUserState1);
testUserState2.suspendedLauncherExtras = launcherExtras2;
assertThat(testUserState1.equals(testUserState2), is(false));
- // Everything is different but irrelevant if suspended is false
+ testUserState2 = new PackageUserState(testUserState1);
+ testUserState2.dialogMessage = dialogMessage2;
+ assertThat(testUserState1.equals(testUserState2), is(false));
+
+ testUserState2 = new PackageUserState(testUserState1);
testUserState2.suspended = testUserState1.suspended = false;
- testUserState2.suspendedAppExtras = appExtras2;
+ // Everything is different but irrelevant if suspended is false
testUserState2.suspendingPackage = suspendingPackage2;
+ testUserState2.dialogMessage = dialogMessage2;
+ testUserState2.suspendedAppExtras = appExtras2;
+ testUserState2.suspendedLauncherExtras = launcherExtras2;
assertThat(testUserState1.equals(testUserState2), is(true));
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
index 43a439b..36e4753 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.app.AppGlobals;
import android.content.BroadcastReceiver;
@@ -41,8 +42,15 @@
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
import android.util.Log;
+import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
+import com.android.servicestests.apps.suspendtestapp.SuspendTestActivity;
import com.android.servicestests.apps.suspendtestapp.SuspendTestReceiver;
import org.junit.After;
@@ -68,14 +76,25 @@
INSTRUMENTATION_PACKAGE + ".action.REPORT_MY_PACKAGE_SUSPENDED";
public static final String ACTION_REPORT_MY_PACKAGE_UNSUSPENDED =
INSTRUMENTATION_PACKAGE + ".action.REPORT_MY_PACKAGE_UNSUSPENDED";
+ public static final String ACTION_REPORT_TEST_ACTIVITY_STARTED =
+ INSTRUMENTATION_PACKAGE + ".action.REPORT_TEST_ACTIVITY_STARTED";
+ public static final String ACTION_REPORT_TEST_ACTIVITY_STOPPED =
+ INSTRUMENTATION_PACKAGE + ".action.REPORT_TEST_ACTIVITY_STOPPED";
+ public static final String ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED =
+ INSTRUMENTATION_PACKAGE + ".action.REPORT_MORE_DETAILS_ACTIVITY_STARTED";
+ public static final String ACTION_FINISH_TEST_ACTIVITY =
+ INSTRUMENTATION_PACKAGE + ".action.FINISH_TEST_ACTIVITY";
+ public static final String EXTRA_RECEIVED_PACKAGE_NAME =
+ SuspendPackagesTest.INSTRUMENTATION_PACKAGE + ".extra.RECEIVED_PACKAGE_NAME";
+
private Context mContext;
private PackageManager mPackageManager;
private LauncherApps mLauncherApps;
private Handler mReceiverHandler;
- private ComponentName mTestReceiverComponent;
private AppCommunicationReceiver mAppCommsReceiver;
private StubbedCallback mTestCallback;
+ private UiDevice mUiDevice;
private static final class AppCommunicationReceiver extends BroadcastReceiver {
private Context context;
@@ -86,11 +105,12 @@
this.context = context;
}
- void register(Handler handler) {
+ void register(Handler handler, String... actions) {
registered = true;
final IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(ACTION_REPORT_MY_PACKAGE_SUSPENDED);
- intentFilter.addAction(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED);
+ for (String action : actions) {
+ intentFilter.addAction(action);
+ }
context.registerReceiver(this, intentFilter, null, handler);
}
@@ -110,19 +130,28 @@
}
}
- Intent receiveIntentFromApp() {
+ Intent pollForIntent(long secondsToWait) {
if (!registered) {
throw new IllegalStateException("Receiver not registered");
}
final Intent intent;
try {
- intent = intentQueue.poll(5, TimeUnit.SECONDS);
+ intent = intentQueue.poll(secondsToWait, TimeUnit.SECONDS);
} catch (InterruptedException ie) {
throw new RuntimeException("Interrupted while waiting for app broadcast", ie);
}
- assertNotNull("No intent received from app within 5 seconds", intent);
return intent;
}
+
+ void drainPendingBroadcasts() {
+ while (pollForIntent(5) != null);
+ }
+
+ Intent receiveIntentFromApp() {
+ final Intent intentReceived = pollForIntent(5);
+ assertNotNull("No intent received from app within 5 seconds", intentReceived);
+ return intentReceived;
+ }
}
@Before
@@ -131,8 +160,7 @@
mPackageManager = mContext.getPackageManager();
mLauncherApps = (LauncherApps) mContext.getSystemService(Context.LAUNCHER_APPS_SERVICE);
mReceiverHandler = new Handler(Looper.getMainLooper());
- mTestReceiverComponent = new ComponentName(TEST_APP_PACKAGE_NAME,
- SuspendTestReceiver.class.getCanonicalName());
+ mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
IPackageManager ipm = AppGlobals.getPackageManager();
try {
// Otherwise implicit broadcasts will not be delivered.
@@ -151,9 +179,10 @@
private Bundle requestAppAction(String action) throws InterruptedException {
final AtomicReference<Bundle> result = new AtomicReference<>();
final CountDownLatch receiverLatch = new CountDownLatch(1);
-
+ final ComponentName testReceiverComponent = new ComponentName(TEST_APP_PACKAGE_NAME,
+ SuspendTestReceiver.class.getCanonicalName());
final Intent broadcastIntent = new Intent(action)
- .setComponent(mTestReceiverComponent)
+ .setComponent(testReceiverComponent)
.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendOrderedBroadcast(broadcastIntent, null, new BroadcastReceiver() {
@Override
@@ -175,9 +204,10 @@
return extras;
}
- private void suspendTestPackage(PersistableBundle appExtras, PersistableBundle launcherExtras) {
+ private void suspendTestPackage(PersistableBundle appExtras, PersistableBundle launcherExtras,
+ String dialogMessage) {
final String[] unchangedPackages = mPackageManager.setPackagesSuspended(
- PACKAGES_TO_SUSPEND, true, appExtras, launcherExtras, null);
+ PACKAGES_TO_SUSPEND, true, appExtras, launcherExtras, dialogMessage);
assertTrue("setPackagesSuspended returned non-empty list", unchangedPackages.length == 0);
}
@@ -187,6 +217,13 @@
assertTrue("setPackagesSuspended returned non-empty list", unchangedPackages.length == 0);
}
+ private void startTestAppActivity() {
+ final Intent testActivity = new Intent()
+ .setComponent(new ComponentName(TEST_APP_PACKAGE_NAME,
+ SuspendTestActivity.class.getCanonicalName()))
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(testActivity);
+ }
private static boolean areSameExtras(BaseBundle expected, BaseBundle received) {
if (expected != null) {
@@ -199,13 +236,14 @@
}
private static void assertSameExtras(String message, BaseBundle expected, BaseBundle received) {
- assertTrue(message + ": [expected: " + expected + "; received: " + received + "]",
- areSameExtras(expected, received));
+ if (!areSameExtras(expected, received)) {
+ fail(message + ": [expected: " + expected + "; received: " + received + "]");
+ }
}
@Test
public void testIsPackageSuspended() {
- suspendTestPackage(null, null);
+ suspendTestPackage(null, null, null);
assertTrue("isPackageSuspended is false",
mPackageManager.isPackageSuspended(TEST_APP_PACKAGE_NAME));
}
@@ -217,7 +255,7 @@
assertNull(resultFromApp.getBundle(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
final PersistableBundle appExtras = getExtras("testSuspendedStateFromApp", 20, "20", 0.2);
- suspendTestPackage(appExtras, null);
+ suspendTestPackage(appExtras, null, null);
resultFromApp = requestAppAction(SuspendTestReceiver.ACTION_GET_SUSPENDED_STATE);
assertTrue("resultFromApp:suspended is false",
@@ -230,37 +268,39 @@
@Test
public void testMyPackageSuspendedUnsuspended() {
- mAppCommsReceiver.register(mReceiverHandler);
+ mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_SUSPENDED,
+ ACTION_REPORT_MY_PACKAGE_UNSUSPENDED);
+ mAppCommsReceiver.drainPendingBroadcasts();
final PersistableBundle appExtras = getExtras("testMyPackageSuspendBroadcasts", 1, "1", .1);
- suspendTestPackage(appExtras, null);
+ suspendTestPackage(appExtras, null, null);
Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
- assertTrue("MY_PACKAGE_SUSPENDED delivery not reported",
- ACTION_REPORT_MY_PACKAGE_SUSPENDED.equals(intentFromApp.getAction()));
+ assertEquals("MY_PACKAGE_SUSPENDED delivery not reported",
+ ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
assertSameExtras("Received app extras different to the ones supplied", appExtras,
intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
unsuspendTestPackage();
intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
- assertTrue("MY_PACKAGE_UNSUSPENDED delivery not reported",
- ACTION_REPORT_MY_PACKAGE_UNSUSPENDED.equals(intentFromApp.getAction()));
+ assertEquals("MY_PACKAGE_UNSUSPENDED delivery not reported",
+ ACTION_REPORT_MY_PACKAGE_UNSUSPENDED, intentFromApp.getAction());
}
@Test
public void testUpdatingAppExtras() {
- mAppCommsReceiver.register(mReceiverHandler);
+ mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_SUSPENDED);
final PersistableBundle extras1 = getExtras("testMyPackageSuspendedOnChangingExtras", 1,
"1", 0.1);
- suspendTestPackage(extras1, null);
+ suspendTestPackage(extras1, null, null);
Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
- assertTrue("MY_PACKAGE_SUSPENDED delivery not reported",
- ACTION_REPORT_MY_PACKAGE_SUSPENDED.equals(intentFromApp.getAction()));
+ assertEquals("MY_PACKAGE_SUSPENDED delivery not reported",
+ ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
assertSameExtras("Received app extras different to the ones supplied", extras1,
intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
final PersistableBundle extras2 = getExtras("testMyPackageSuspendedOnChangingExtras", 2,
"2", 0.2);
mPackageManager.setSuspendedPackageAppExtras(TEST_APP_PACKAGE_NAME, extras2);
intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
- assertTrue("MY_PACKAGE_SUSPENDED delivery not reported",
- ACTION_REPORT_MY_PACKAGE_SUSPENDED.equals(intentFromApp.getAction()));
+ assertEquals("MY_PACKAGE_SUSPENDED delivery not reported",
+ ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
assertSameExtras("Received app extras different to the updated extras", extras2,
intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
}
@@ -274,12 +314,26 @@
}
@Test
+ public void testActivityStoppedOnSuspend() {
+ mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_TEST_ACTIVITY_STARTED,
+ ACTION_REPORT_TEST_ACTIVITY_STOPPED);
+ startTestAppActivity();
+ Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
+ assertEquals("Test activity start not reported",
+ ACTION_REPORT_TEST_ACTIVITY_STARTED, intentFromApp.getAction());
+ suspendTestPackage(null, null, null);
+ intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
+ assertEquals("Test activity stop not reported on suspending the test app",
+ ACTION_REPORT_TEST_ACTIVITY_STOPPED, intentFromApp.getAction());
+ }
+
+ @Test
public void testGetLauncherExtrasNonNull() {
final Bundle extrasWhenUnsuspended = mLauncherApps.getSuspendedPackageLauncherExtras(
TEST_APP_PACKAGE_NAME, mContext.getUser());
assertNull("Non null extras when package unsuspended:", extrasWhenUnsuspended);
final PersistableBundle launcherExtras = getExtras("testGetLauncherExtras", 1, "1", 0.1);
- suspendTestPackage(null, launcherExtras);
+ suspendTestPackage(null, launcherExtras, null);
final Bundle receivedExtras = mLauncherApps.getSuspendedPackageLauncherExtras(
TEST_APP_PACKAGE_NAME, mContext.getUser());
assertSameExtras("Received launcher extras different to the ones supplied", launcherExtras,
@@ -288,7 +342,7 @@
@Test
public void testGetLauncherExtrasNull() {
- suspendTestPackage(null, null);
+ suspendTestPackage(null, null, null);
final Bundle extrasWhenNoneGiven = mLauncherApps.getSuspendedPackageLauncherExtras(
TEST_APP_PACKAGE_NAME, mContext.getUser());
assertNull("Non null extras when null extras provided:", extrasWhenNoneGiven);
@@ -339,7 +393,7 @@
}
};
mLauncherApps.registerCallback(mTestCallback, mReceiverHandler);
- suspendTestPackage(null, suppliedExtras);
+ suspendTestPackage(null, suppliedExtras, null);
assertFalse("Both callbacks were invoked", twoCallbackLatch.await(5, TimeUnit.SECONDS));
twoCallbackLatch.countDown();
assertTrue("No callback was invoked", twoCallbackLatch.await(2, TimeUnit.SECONDS));
@@ -373,19 +427,53 @@
}
};
mLauncherApps.registerCallback(mTestCallback, mReceiverHandler);
- suspendTestPackage(null, suppliedExtras);
+ suspendTestPackage(null, suppliedExtras, null);
assertTrue("Callback not invoked", oneCallbackLatch.await(5, TimeUnit.SECONDS));
final String result = overridingOneCallbackResult.get();
assertTrue("Callback did not complete as expected: " + result, result.isEmpty());
}
+ private void turnScreenOn() throws Exception {
+ if (!mUiDevice.isScreenOn()) {
+ mUiDevice.wakeUp();
+ }
+ final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ wm.dismissKeyguard(null, null);
+ }
+
+ @Test
+ public void testInterceptorActivity() throws Exception {
+ turnScreenOn();
+ mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED,
+ ACTION_REPORT_TEST_ACTIVITY_STARTED);
+ final String testMessage = "This is a test message";
+ suspendTestPackage(null, null, testMessage);
+ startTestAppActivity();
+ assertNull("No broadcast was expected from app", mAppCommsReceiver.pollForIntent(2));
+ assertNotNull("Given dialog message not shown",
+ mUiDevice.wait(Until.findObject(By.text(testMessage)), 5000));
+ final String buttonText = "More details";
+ final UiObject2 moreDetailsButton = mUiDevice.findObject(
+ By.clickable(true).text(buttonText));
+ assertNotNull("\"More Details\" button not shown", moreDetailsButton);
+ moreDetailsButton.click();
+ final Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
+ assertEquals("\"More Details\" activity start not reported",
+ ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED, intentFromApp.getAction());
+ final String receivedPackageName = intentFromApp.getStringExtra(
+ EXTRA_RECEIVED_PACKAGE_NAME);
+ assertEquals("Wrong package name received by \"More Details\" activity",
+ TEST_APP_PACKAGE_NAME, receivedPackageName);
+ }
+
@After
- public void tearDown() throws Exception {
+ public void tearDown() {
mAppCommsReceiver.unregister();
if (mTestCallback != null) {
mLauncherApps.unregisterCallback(mTestCallback);
}
- Thread.sleep(250); // To prevent any race with the next registerReceiver
+ mContext.sendBroadcast(new Intent(ACTION_FINISH_TEST_ACTIVITY)
+ .setPackage(TEST_APP_PACKAGE_NAME));
}
private static abstract class StubbedCallback extends LauncherApps.Callback {
diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendedDetailsActivity.java b/services/tests/servicestests/src/com/android/server/pm/SuspendedDetailsActivity.java
new file mode 100644
index 0000000..18f0123
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/SuspendedDetailsActivity.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 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.pm;
+
+import static com.android.server.pm.SuspendPackagesTest.ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED;
+import static com.android.server.pm.SuspendPackagesTest.EXTRA_RECEIVED_PACKAGE_NAME;
+import static com.android.server.pm.SuspendPackagesTest.INSTRUMENTATION_PACKAGE;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+public class SuspendedDetailsActivity extends Activity {
+ private static final String TAG = SuspendedDetailsActivity.class.getSimpleName();
+
+ @Override
+ protected void onStart() {
+ Log.d(TAG, "onStart");
+ final String suspendedPackage = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+ super.onStart();
+ final Intent reportStart = new Intent(ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED)
+ .putExtra(EXTRA_RECEIVED_PACKAGE_NAME, suspendedPackage)
+ .setPackage(INSTRUMENTATION_PACKAGE);
+ sendBroadcast(reportStart);
+ finish();
+ }
+}
diff --git a/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk b/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk
index afdde72..ae0b0f9 100644
--- a/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk
+++ b/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk
@@ -20,7 +20,7 @@
LOCAL_COMPATIBILITY_SUITE := device-tests
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_SRC_FILES += ../../src/com/android/server/pm/SuspendPackagesTest.java
diff --git a/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestActivity.java b/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestActivity.java
index fa5fc58..ab7ddbb 100644
--- a/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestActivity.java
+++ b/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestActivity.java
@@ -16,9 +16,45 @@
package com.android.servicestests.apps.suspendtestapp;
+import static com.android.server.pm.SuspendPackagesTest.ACTION_FINISH_TEST_ACTIVITY;
+import static com.android.server.pm.SuspendPackagesTest.ACTION_REPORT_TEST_ACTIVITY_STARTED;
+import static com.android.server.pm.SuspendPackagesTest.ACTION_REPORT_TEST_ACTIVITY_STOPPED;
+import static com.android.server.pm.SuspendPackagesTest.INSTRUMENTATION_PACKAGE;
+
import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
public class SuspendTestActivity extends Activity {
private static final String TAG = SuspendTestActivity.class.getSimpleName();
-}
\ No newline at end of file
+ private BroadcastReceiver mFinishReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.d(TAG, "Finishing test activity from receiver");
+ SuspendTestActivity.this.finish();
+ }
+ };
+
+ @Override
+ public void onStart() {
+ Log.d(TAG, "onStart");
+ final Intent reportStart = new Intent(ACTION_REPORT_TEST_ACTIVITY_STARTED)
+ .setPackage(INSTRUMENTATION_PACKAGE);
+ sendBroadcast(reportStart);
+ registerReceiver(mFinishReceiver, new IntentFilter(ACTION_FINISH_TEST_ACTIVITY));
+ super.onStart();
+ }
+ @Override
+ public void onStop() {
+ Log.d(TAG, "onStop");
+ final Intent reportStop = new Intent(ACTION_REPORT_TEST_ACTIVITY_STOPPED)
+ .setPackage(INSTRUMENTATION_PACKAGE);
+ sendBroadcast(reportStop);
+ unregisterReceiver(mFinishReceiver);
+ super.onStop();
+ }
+}