Merge "Update battery defender strings" into sc-dev
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index b3c33b6..144536e 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -1229,7 +1229,11 @@
* </ul>
* Note that the system may choose to delay jobs with large network
* usage estimates when the device has a poor network connection, in
- * order to save battery.
+ * order to save battery and possible network costs.
+ * Starting from Android version {@link Build.VERSION_CODES#S}, JobScheduler may attempt
+ * to run large jobs when the device is charging and on an unmetered network, even if the
+ * network is slow. This gives large jobs an opportunity to make forward progress, even if
+ * they risk timing out.
* <p>
* The values provided here only reflect the traffic that will be
* performed by the base job; if you're using {@link JobWorkItem} then
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 60f5769..cef065d 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -547,7 +547,7 @@
private int[] mPowerSaveWhitelistUserAppIdArray = new int[0];
/**
- * List of end times for UIDs that are temporarily marked as being allowed to access
+ * List of end times for app-IDs that are temporarily marked as being allowed to access
* the network and acquire wakelocks. Times are in milliseconds.
*/
private final SparseArray<Pair<MutableLong, String>> mTempWhitelistAppIdEndTimes
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 5365218..1169391 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -121,7 +121,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
-import com.android.internal.os.BinderDeathDispatcher;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.LocalLog;
@@ -184,8 +183,7 @@
static final boolean DEBUG_BG_LIMIT = localLOGV || false;
static final boolean DEBUG_STANDBY = localLOGV || false;
static final boolean RECORD_ALARMS_IN_HISTORY = true;
- // TODO(b/178484639) : Turn off once alarms and reminders work is complete.
- static final boolean RECORD_DEVICE_IDLE_ALARMS = true;
+ static final boolean RECORD_DEVICE_IDLE_ALARMS = false;
static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
static final int TICK_HISTORY_DEPTH = 10;
@@ -206,8 +204,6 @@
.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
| Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
- private static final BinderDeathDispatcher<IAlarmListener> sListenerDeathDispatcher =
- new BinderDeathDispatcher<>();
final LocalLog mLog = new LocalLog(TAG);
AppOpsManager mAppOps;
@@ -1837,8 +1833,9 @@
}
if (directReceiver != null) {
- if (sListenerDeathDispatcher.linkToDeath(directReceiver, mListenerDeathRecipient)
- <= 0) {
+ try {
+ directReceiver.asBinder().linkToDeath(mListenerDeathRecipient, 0);
+ } catch (RemoteException e) {
Slog.w(TAG, "Dropping unreachable alarm listener " + listenerTag);
return;
}
@@ -2851,12 +2848,6 @@
pw.println();
}
- pw.println("Listener death dispatcher state:");
- pw.increaseIndent();
- sListenerDeathDispatcher.dump(pw);
- pw.println();
- pw.decreaseIndent();
-
if (mLog.dump(pw, "Recent problems:")) {
pw.println();
}
@@ -3448,6 +3439,9 @@
for (final Alarm removed : removedAlarms) {
decrementAlarmCount(removed.uid, 1);
+ if (removed.listener != null) {
+ removed.listener.asBinder().unlinkToDeath(mListenerDeathRecipient, 0);
+ }
if (!RemovedAlarm.isLoggable(reason)) {
continue;
}
@@ -4701,6 +4695,8 @@
// Direct listener callback alarm
mListenerCount++;
+ alarm.listener.asBinder().unlinkToDeath(mListenerDeathRecipient, 0);
+
if (RECORD_ALARMS_IN_HISTORY) {
if (alarm.listener == mTimeTickTrigger) {
mTickHistory[mNextTickHistory++] = nowELAPSED;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index 7b947fd..e8065aa 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -25,12 +25,18 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.job.JobInfo;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkPolicyManager;
import android.net.NetworkRequest;
+import android.os.BatteryManager;
+import android.os.BatteryManagerInternal;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -101,6 +107,8 @@
private final ConnectivityManager mConnManager;
private final NetworkPolicyManagerInternal mNetPolicyManagerInternal;
+ private final ChargingTracker mChargingTracker;
+
/** List of tracked jobs keyed by source UID. */
@GuardedBy("mLock")
private final SparseArray<ArraySet<JobStatus>> mTrackedJobs = new SparseArray<>();
@@ -229,6 +237,9 @@
// network changes against the active network for each UID with jobs.
final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
mConnManager.registerNetworkCallback(request, mNetworkCallback);
+
+ mChargingTracker = new ChargingTracker();
+ mChargingTracker.startTracking();
}
@GuardedBy("mLock")
@@ -538,6 +549,14 @@
*/
private boolean isInsane(JobStatus jobStatus, Network network,
NetworkCapabilities capabilities, Constants constants) {
+ if (capabilities.hasCapability(NET_CAPABILITY_NOT_METERED)
+ && mChargingTracker.isCharging()) {
+ // We're charging and on an unmetered network. We don't have to be as conservative about
+ // making sure the job will run within its max execution time. Let's just hope the app
+ // supports interruptible work.
+ return false;
+ }
+
// Use the maximum possible time since it gives us an upper bound, even though the job
// could end up stopping earlier.
final long maxJobExecutionTimeMs = mService.getMaxJobExecutionTimeMs(jobStatus);
@@ -922,7 +941,7 @@
* {@link Network}, or {@code null} to update all tracked jobs.
*/
@GuardedBy("mLock")
- private void updateTrackedJobsLocked(int filterUid, Network filterNetwork) {
+ private void updateTrackedJobsLocked(int filterUid, @Nullable Network filterNetwork) {
boolean changed = false;
if (filterUid == -1) {
for (int i = mTrackedJobs.size() - 1; i >= 0; i--) {
@@ -937,7 +956,8 @@
}
@GuardedBy("mLock")
- private boolean updateTrackedJobsLocked(ArraySet<JobStatus> jobs, Network filterNetwork) {
+ private boolean updateTrackedJobsLocked(ArraySet<JobStatus> jobs,
+ @Nullable Network filterNetwork) {
if (jobs == null || jobs.size() == 0) {
return false;
}
@@ -993,6 +1013,51 @@
}
}
+ private final class ChargingTracker extends BroadcastReceiver {
+ /**
+ * Track whether we're "charging", where charging means that we're ready to commit to
+ * doing work.
+ */
+ private boolean mCharging;
+
+ ChargingTracker() {}
+
+ public void startTracking() {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(BatteryManager.ACTION_CHARGING);
+ filter.addAction(BatteryManager.ACTION_DISCHARGING);
+ mContext.registerReceiver(this, filter);
+
+ // Initialise tracker state.
+ final BatteryManagerInternal batteryManagerInternal =
+ LocalServices.getService(BatteryManagerInternal.class);
+ mCharging = batteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
+ }
+
+ public boolean isCharging() {
+ return mCharging;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ synchronized (mLock) {
+ final String action = intent.getAction();
+ if (BatteryManager.ACTION_CHARGING.equals(action)) {
+ if (mCharging) {
+ return;
+ }
+ mCharging = true;
+ } else if (BatteryManager.ACTION_DISCHARGING.equals(action)) {
+ if (!mCharging) {
+ return;
+ }
+ mCharging = false;
+ }
+ updateTrackedJobsLocked(-1, null);
+ }
+ }
+ }
+
private final NetworkCallback mNetworkCallback = new NetworkCallback() {
@Override
public void onAvailable(Network network) {
diff --git a/apex/media/service/Android.bp b/apex/media/service/Android.bp
index 9b3399e..271fc53 100644
--- a/apex/media/service/Android.bp
+++ b/apex/media/service/Android.bp
@@ -23,10 +23,10 @@
filegroup {
name: "service-media-s-sources",
srcs: [
- "java/**/*.java",
+ "java/**/*.java",
],
path: "java",
- visibility: ["//frameworks/base/services"], // TODO(b/177640454): Should be private.
+ visibility: ["//visibility:private"],
}
java_sdk_library {
diff --git a/boot/Android.bp b/boot/Android.bp
index 3caede4..e8d88a5 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -48,13 +48,57 @@
// bootclasspath.
fragments: [
{
+ apex: "com.android.appsearch",
+ module: "com.android.appsearch-bootclasspath-fragment",
+ },
+ {
apex: "com.android.art",
module: "art-bootclasspath-fragment",
},
{
+ apex: "com.android.conscrypt",
+ module: "com.android.conscrypt-bootclasspath-fragment",
+ },
+ {
apex: "com.android.i18n",
module: "i18n-bootclasspath-fragment",
},
+ {
+ apex: "com.android.ipsec",
+ module: "com.android.ipsec-bootclasspath-fragment",
+ },
+ {
+ apex: "com.android.media",
+ module: "com.android.media-bootclasspath-fragment",
+ },
+ {
+ apex: "com.android.mediaprovider",
+ module: "com.android.mediaprovider-bootclasspath-fragment",
+ },
+ {
+ apex: "com.android.os.statsd",
+ module: "com.android.os.statsd-bootclasspath-fragment",
+ },
+ {
+ apex: "com.android.permission",
+ module: "com.android.permission-bootclasspath-fragment",
+ },
+ {
+ apex: "com.android.scheduling",
+ module: "com.android.scheduling-bootclasspath-fragment",
+ },
+ {
+ apex: "com.android.sdkext",
+ module: "com.android.sdkext-bootclasspath-fragment",
+ },
+ {
+ apex: "com.android.tethering",
+ module: "com.android.tethering-bootclasspath-fragment",
+ },
+ {
+ apex: "com.android.wifi",
+ module: "com.android.wifi-bootclasspath-fragment",
+ },
],
// Additional information needed by hidden api processing.
diff --git a/boot/hiddenapi/hiddenapi-max-target-o.txt b/boot/hiddenapi/hiddenapi-max-target-o.txt
index 45ebbb1..3cc28d9 100644
--- a/boot/hiddenapi/hiddenapi-max-target-o.txt
+++ b/boot/hiddenapi/hiddenapi-max-target-o.txt
@@ -93863,283 +93863,6 @@
Lcom/android/internal/widget/VerifyCredentialResponse;->setTimeout(I)V
Lcom/android/internal/widget/VerifyCredentialResponse;->stripPayload()Lcom/android/internal/widget/VerifyCredentialResponse;
Lcom/android/internal/widget/VerifyCredentialResponse;->TAG:Ljava/lang/String;
-Lcom/android/org/conscrypt/AbstractConscryptSocket;-><init>()V
-Lcom/android/org/conscrypt/AbstractConscryptSocket;-><init>(Ljava/lang/String;I)V
-Lcom/android/org/conscrypt/AbstractConscryptSocket;-><init>(Ljava/lang/String;ILjava/net/InetAddress;I)V
-Lcom/android/org/conscrypt/AbstractConscryptSocket;-><init>(Ljava/net/InetAddress;I)V
-Lcom/android/org/conscrypt/AbstractConscryptSocket;-><init>(Ljava/net/InetAddress;ILjava/net/InetAddress;I)V
-Lcom/android/org/conscrypt/AbstractConscryptSocket;->getFileDescriptor$()Ljava/io/FileDescriptor;
-Lcom/android/org/conscrypt/AbstractConscryptSocket;->getTlsUnique()[B
-Lcom/android/org/conscrypt/AbstractConscryptSocket;->peerInfoProvider()Lcom/android/org/conscrypt/PeerInfoProvider;
-Lcom/android/org/conscrypt/AbstractConscryptSocket;->setApplicationProtocolSelector(Lcom/android/org/conscrypt/ApplicationProtocolSelector;)V
-Lcom/android/org/conscrypt/ApplicationProtocolSelector;-><init>()V
-Lcom/android/org/conscrypt/ApplicationProtocolSelector;->selectApplicationProtocol(Ljavax/net/ssl/SSLEngine;Ljava/util/List;)Ljava/lang/String;
-Lcom/android/org/conscrypt/ApplicationProtocolSelector;->selectApplicationProtocol(Ljavax/net/ssl/SSLSocket;Ljava/util/List;)Ljava/lang/String;
-Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;-><init>(Ljavax/net/ssl/SSLEngine;Lcom/android/org/conscrypt/ApplicationProtocolSelector;)V
-Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;-><init>(Ljavax/net/ssl/SSLSocket;Lcom/android/org/conscrypt/ApplicationProtocolSelector;)V
-Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;->engine:Ljavax/net/ssl/SSLEngine;
-Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;->NO_PROTOCOL_SELECTED:I
-Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;->selectApplicationProtocol([B)I
-Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;->selector:Lcom/android/org/conscrypt/ApplicationProtocolSelector;
-Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;->socket:Ljavax/net/ssl/SSLSocket;
-Lcom/android/org/conscrypt/CertBlacklist;-><init>(Ljava/util/Set;Ljava/util/Set;)V
-Lcom/android/org/conscrypt/CertBlacklist;->closeQuietly(Ljava/io/Closeable;)V
-Lcom/android/org/conscrypt/CertBlacklist;->getDefault()Lcom/android/org/conscrypt/CertBlacklist;
-Lcom/android/org/conscrypt/CertBlacklist;->HEX_TABLE:[B
-Lcom/android/org/conscrypt/CertBlacklist;->isHex(Ljava/lang/String;)Z
-Lcom/android/org/conscrypt/CertBlacklist;->isPubkeyHash(Ljava/lang/String;)Z
-Lcom/android/org/conscrypt/CertBlacklist;->isPublicKeyBlackListed(Ljava/security/PublicKey;)Z
-Lcom/android/org/conscrypt/CertBlacklist;->isSerialNumberBlackListed(Ljava/math/BigInteger;)Z
-Lcom/android/org/conscrypt/CertBlacklist;->logger:Ljava/util/logging/Logger;
-Lcom/android/org/conscrypt/CertBlacklist;->pubkeyBlacklist:Ljava/util/Set;
-Lcom/android/org/conscrypt/CertBlacklist;->readBlacklist(Ljava/lang/String;)Ljava/lang/String;
-Lcom/android/org/conscrypt/CertBlacklist;->readFileAsBytes(Ljava/lang/String;)Ljava/io/ByteArrayOutputStream;
-Lcom/android/org/conscrypt/CertBlacklist;->readFileAsString(Ljava/lang/String;)Ljava/lang/String;
-Lcom/android/org/conscrypt/CertBlacklist;->readPublicKeyBlackList(Ljava/lang/String;)Ljava/util/Set;
-Lcom/android/org/conscrypt/CertBlacklist;->readSerialBlackList(Ljava/lang/String;)Ljava/util/Set;
-Lcom/android/org/conscrypt/CertBlacklist;->serialBlacklist:Ljava/util/Set;
-Lcom/android/org/conscrypt/CertBlacklist;->toHex([B)[B
-Lcom/android/org/conscrypt/CertificatePriorityComparator;-><init>()V
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->ALGORITHM_OID_PRIORITY_MAP:Ljava/util/Map;
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->compare(Ljava/lang/Object;Ljava/lang/Object;)I
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->compare(Ljava/security/cert/X509Certificate;Ljava/security/cert/X509Certificate;)I
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->compareKeyAlgorithm(Ljava/security/PublicKey;Ljava/security/PublicKey;)I
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->compareKeySize(Ljava/security/PublicKey;Ljava/security/PublicKey;)I
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->compareSignatureAlgorithm(Ljava/security/cert/X509Certificate;Ljava/security/cert/X509Certificate;)I
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->compareStrength(Ljava/security/cert/X509Certificate;Ljava/security/cert/X509Certificate;)I
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->getKeySize(Ljava/security/PublicKey;)I
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->PRIORITY_MD5:Ljava/lang/Integer;
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->PRIORITY_SHA1:Ljava/lang/Integer;
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->PRIORITY_SHA224:Ljava/lang/Integer;
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->PRIORITY_SHA256:Ljava/lang/Integer;
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->PRIORITY_SHA384:Ljava/lang/Integer;
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->PRIORITY_SHA512:Ljava/lang/Integer;
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->PRIORITY_UNKNOWN:Ljava/lang/Integer;
-Lcom/android/org/conscrypt/CertPinManager;->checkChainPinning(Ljava/lang/String;Ljava/util/List;)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;-><init>()V
-Lcom/android/org/conscrypt/ConscryptSocketBase;-><init>(Ljava/lang/String;I)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;-><init>(Ljava/lang/String;ILjava/net/InetAddress;I)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;-><init>(Ljava/net/InetAddress;I)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;-><init>(Ljava/net/InetAddress;ILjava/net/InetAddress;I)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;-><init>(Ljava/net/Socket;Ljava/lang/String;IZ)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;->autoClose:Z
-Lcom/android/org/conscrypt/ConscryptSocketBase;->checkOpen()V
-Lcom/android/org/conscrypt/ConscryptSocketBase;->getActiveSession()Ljavax/net/ssl/SSLSession;
-Lcom/android/org/conscrypt/ConscryptSocketBase;->getFileDescriptor$()Ljava/io/FileDescriptor;
-Lcom/android/org/conscrypt/ConscryptSocketBase;->isDelegating()Z
-Lcom/android/org/conscrypt/ConscryptSocketBase;->listeners:Ljava/util/List;
-Lcom/android/org/conscrypt/ConscryptSocketBase;->notifyHandshakeCompletedListeners()V
-Lcom/android/org/conscrypt/ConscryptSocketBase;->peerHostname:Ljava/lang/String;
-Lcom/android/org/conscrypt/ConscryptSocketBase;->peerInfoProvider()Lcom/android/org/conscrypt/PeerInfoProvider;
-Lcom/android/org/conscrypt/ConscryptSocketBase;->peerInfoProvider:Lcom/android/org/conscrypt/PeerInfoProvider;
-Lcom/android/org/conscrypt/ConscryptSocketBase;->peerPort:I
-Lcom/android/org/conscrypt/ConscryptSocketBase;->readTimeoutMilliseconds:I
-Lcom/android/org/conscrypt/ConscryptSocketBase;->setApplicationProtocolSelector(Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;)V
-Lcom/android/org/conscrypt/NativeRef$EC_GROUP;-><init>(J)V
-Lcom/android/org/conscrypt/NativeRef$EC_GROUP;->doFree(J)V
-Lcom/android/org/conscrypt/NativeRef$EC_POINT;-><init>(J)V
-Lcom/android/org/conscrypt/NativeRef$EC_POINT;->doFree(J)V
-Lcom/android/org/conscrypt/NativeRef$EVP_CIPHER_CTX;-><init>(J)V
-Lcom/android/org/conscrypt/NativeRef$EVP_CIPHER_CTX;->doFree(J)V
-Lcom/android/org/conscrypt/NativeRef$EVP_MD_CTX;-><init>(J)V
-Lcom/android/org/conscrypt/NativeRef$EVP_MD_CTX;->doFree(J)V
-Lcom/android/org/conscrypt/NativeRef$EVP_PKEY;-><init>(J)V
-Lcom/android/org/conscrypt/NativeRef$EVP_PKEY;->doFree(J)V
-Lcom/android/org/conscrypt/NativeRef$EVP_PKEY_CTX;-><init>(J)V
-Lcom/android/org/conscrypt/NativeRef$EVP_PKEY_CTX;->doFree(J)V
-Lcom/android/org/conscrypt/NativeRef$HMAC_CTX;-><init>(J)V
-Lcom/android/org/conscrypt/NativeRef$HMAC_CTX;->doFree(J)V
-Lcom/android/org/conscrypt/NativeRef$SSL_SESSION;-><init>(J)V
-Lcom/android/org/conscrypt/NativeRef$SSL_SESSION;->doFree(J)V
-Lcom/android/org/conscrypt/NativeRef;-><init>(J)V
-Lcom/android/org/conscrypt/NativeRef;->context:J
-Lcom/android/org/conscrypt/NativeRef;->doFree(J)V
-Lcom/android/org/conscrypt/OpenSSLKey;-><init>(JZ)V
-Lcom/android/org/conscrypt/OpenSSLKey;->ctx:Lcom/android/org/conscrypt/NativeRef$EVP_PKEY;
-Lcom/android/org/conscrypt/OpenSSLKey;->fromECPrivateKeyForTLSStackOnly(Ljava/security/PrivateKey;Ljava/security/spec/ECParameterSpec;)Lcom/android/org/conscrypt/OpenSSLKey;
-Lcom/android/org/conscrypt/OpenSSLKey;->fromKeyMaterial(Ljava/security/PrivateKey;)Lcom/android/org/conscrypt/OpenSSLKey;
-Lcom/android/org/conscrypt/OpenSSLKey;->fromPrivateKeyForTLSStackOnly(Ljava/security/PrivateKey;Ljava/security/PublicKey;)Lcom/android/org/conscrypt/OpenSSLKey;
-Lcom/android/org/conscrypt/OpenSSLKey;->fromPrivateKeyPemInputStream(Ljava/io/InputStream;)Lcom/android/org/conscrypt/OpenSSLKey;
-Lcom/android/org/conscrypt/OpenSSLKey;->fromPublicKey(Ljava/security/PublicKey;)Lcom/android/org/conscrypt/OpenSSLKey;
-Lcom/android/org/conscrypt/OpenSSLKey;->fromPublicKeyPemInputStream(Ljava/io/InputStream;)Lcom/android/org/conscrypt/OpenSSLKey;
-Lcom/android/org/conscrypt/OpenSSLKey;->getOpenSSLKey(Ljava/security/PrivateKey;)Lcom/android/org/conscrypt/OpenSSLKey;
-Lcom/android/org/conscrypt/OpenSSLKey;->getPrivateKey()Ljava/security/PrivateKey;
-Lcom/android/org/conscrypt/OpenSSLKey;->getPrivateKey(Ljava/security/spec/PKCS8EncodedKeySpec;I)Ljava/security/PrivateKey;
-Lcom/android/org/conscrypt/OpenSSLKey;->getPublicKey(Ljava/security/spec/X509EncodedKeySpec;I)Ljava/security/PublicKey;
-Lcom/android/org/conscrypt/OpenSSLKey;->isWrapped()Z
-Lcom/android/org/conscrypt/OpenSSLKey;->wrapJCAPrivateKeyForTLSStackOnly(Ljava/security/PrivateKey;Ljava/security/PublicKey;)Lcom/android/org/conscrypt/OpenSSLKey;
-Lcom/android/org/conscrypt/OpenSSLKey;->wrapped:Z
-Lcom/android/org/conscrypt/OpenSSLKey;->wrapPrivateKey(Ljava/security/PrivateKey;)Lcom/android/org/conscrypt/OpenSSLKey;
-Lcom/android/org/conscrypt/OpenSSLSocketImpl;-><init>()V
-Lcom/android/org/conscrypt/OpenSSLSocketImpl;-><init>(Ljava/lang/String;I)V
-Lcom/android/org/conscrypt/OpenSSLSocketImpl;-><init>(Ljava/lang/String;ILjava/net/InetAddress;I)V
-Lcom/android/org/conscrypt/OpenSSLSocketImpl;-><init>(Ljava/net/InetAddress;I)V
-Lcom/android/org/conscrypt/OpenSSLSocketImpl;-><init>(Ljava/net/InetAddress;ILjava/net/InetAddress;I)V
-Lcom/android/org/conscrypt/OpenSSLSocketImpl;-><init>(Ljava/net/Socket;Ljava/lang/String;IZ)V
-Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getFileDescriptor$()Ljava/io/FileDescriptor;
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;-><init>(J)V
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;-><init>(JLjava/util/Date;Ljava/util/Date;)V
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->alternativeNameArrayToList([[Ljava/lang/Object;)Ljava/util/Collection;
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->fromCertificate(Ljava/security/cert/Certificate;)Lcom/android/org/conscrypt/OpenSSLX509Certificate;
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->fromPkcs7DerInputStream(Ljava/io/InputStream;)Ljava/util/List;
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->fromPkcs7PemInputStream(Ljava/io/InputStream;)Ljava/util/List;
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->fromX509Der([B)Lcom/android/org/conscrypt/OpenSSLX509Certificate;
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->fromX509DerInputStream(Ljava/io/InputStream;)Lcom/android/org/conscrypt/OpenSSLX509Certificate;
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->getContext()J
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->mHashCode:Ljava/lang/Integer;
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->notAfter:Ljava/util/Date;
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->notBefore:Ljava/util/Date;
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->toDate(J)Ljava/util/Date;
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->verifyInternal(Ljava/security/PublicKey;Ljava/lang/String;)V
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->verifyOpenSSL(Lcom/android/org/conscrypt/OpenSSLKey;)V
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->withDeletedExtension(Ljava/lang/String;)Lcom/android/org/conscrypt/OpenSSLX509Certificate;
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;-><init>()V
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;->fromPkcs7DerInputStream(Ljava/io/InputStream;)Ljava/util/List;
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;->fromPkcs7PemInputStream(Ljava/io/InputStream;)Ljava/util/List;
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;->fromX509DerInputStream(Ljava/io/InputStream;)Ljava/lang/Object;
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;->fromX509PemInputStream(Ljava/io/InputStream;)Ljava/lang/Object;
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;->generateItem(Ljava/io/InputStream;)Ljava/lang/Object;
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;->generateItems(Ljava/io/InputStream;)Ljava/util/Collection;
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$ParsingException;-><init>(Ljava/lang/Exception;)V
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$ParsingException;-><init>(Ljava/lang/String;)V
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$ParsingException;-><init>(Ljava/lang/String;Ljava/lang/Exception;)V
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory;-><init>()V
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory;->certificateParser:Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory;->crlParser:Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory;->PKCS7_MARKER:[B
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory;->PUSHBACK_SIZE:I
-Lcom/android/org/conscrypt/OpenSSLX509CRL;-><init>(J)V
-Lcom/android/org/conscrypt/OpenSSLX509CRL;->fromPkcs7DerInputStream(Ljava/io/InputStream;)Ljava/util/List;
-Lcom/android/org/conscrypt/OpenSSLX509CRL;->fromPkcs7PemInputStream(Ljava/io/InputStream;)Ljava/util/List;
-Lcom/android/org/conscrypt/OpenSSLX509CRL;->fromX509DerInputStream(Ljava/io/InputStream;)Lcom/android/org/conscrypt/OpenSSLX509CRL;
-Lcom/android/org/conscrypt/OpenSSLX509CRL;->fromX509PemInputStream(Ljava/io/InputStream;)Lcom/android/org/conscrypt/OpenSSLX509CRL;
-Lcom/android/org/conscrypt/OpenSSLX509CRL;->mContext:J
-Lcom/android/org/conscrypt/OpenSSLX509CRL;->nextUpdate:Ljava/util/Date;
-Lcom/android/org/conscrypt/OpenSSLX509CRL;->thisUpdate:Ljava/util/Date;
-Lcom/android/org/conscrypt/OpenSSLX509CRL;->toDate(J)Ljava/util/Date;
-Lcom/android/org/conscrypt/OpenSSLX509CRL;->verifyInternal(Ljava/security/PublicKey;Ljava/lang/String;)V
-Lcom/android/org/conscrypt/OpenSSLX509CRL;->verifyOpenSSL(Lcom/android/org/conscrypt/OpenSSLKey;)V
-Lcom/android/org/conscrypt/PeerInfoProvider;-><init>()V
-Lcom/android/org/conscrypt/PeerInfoProvider;->forHostAndPort(Ljava/lang/String;I)Lcom/android/org/conscrypt/PeerInfoProvider;
-Lcom/android/org/conscrypt/PeerInfoProvider;->getHostname()Ljava/lang/String;
-Lcom/android/org/conscrypt/PeerInfoProvider;->getHostnameOrIP()Ljava/lang/String;
-Lcom/android/org/conscrypt/PeerInfoProvider;->getPort()I
-Lcom/android/org/conscrypt/PeerInfoProvider;->nullProvider()Lcom/android/org/conscrypt/PeerInfoProvider;
-Lcom/android/org/conscrypt/PeerInfoProvider;->NULL_PEER_INFO_PROVIDER:Lcom/android/org/conscrypt/PeerInfoProvider;
-Lcom/android/org/conscrypt/SSLClientSessionCache;->getSessionData(Ljava/lang/String;I)[B
-Lcom/android/org/conscrypt/SSLClientSessionCache;->putSessionData(Ljavax/net/ssl/SSLSession;[B)V
-Lcom/android/org/conscrypt/TrustedCertificateIndex;-><init>()V
-Lcom/android/org/conscrypt/TrustedCertificateIndex;-><init>(Ljava/util/Set;)V
-Lcom/android/org/conscrypt/TrustedCertificateIndex;->findAllByIssuerAndSignature(Ljava/security/cert/X509Certificate;)Ljava/util/Set;
-Lcom/android/org/conscrypt/TrustedCertificateIndex;->findByIssuerAndSignature(Ljava/security/cert/X509Certificate;)Ljava/security/cert/TrustAnchor;
-Lcom/android/org/conscrypt/TrustedCertificateIndex;->findBySubjectAndPublicKey(Ljava/security/cert/X509Certificate;)Ljava/security/cert/TrustAnchor;
-Lcom/android/org/conscrypt/TrustedCertificateIndex;->findBySubjectAndPublicKey(Ljava/security/cert/X509Certificate;Ljava/util/Collection;)Ljava/security/cert/TrustAnchor;
-Lcom/android/org/conscrypt/TrustedCertificateIndex;->index(Ljava/security/cert/TrustAnchor;)V
-Lcom/android/org/conscrypt/TrustedCertificateIndex;->index(Ljava/security/cert/X509Certificate;)Ljava/security/cert/TrustAnchor;
-Lcom/android/org/conscrypt/TrustedCertificateIndex;->index(Ljava/util/Set;)V
-Lcom/android/org/conscrypt/TrustedCertificateIndex;->reset()V
-Lcom/android/org/conscrypt/TrustedCertificateIndex;->reset(Ljava/util/Set;)V
-Lcom/android/org/conscrypt/TrustedCertificateIndex;->subjectToTrustAnchors:Ljava/util/Map;
-Lcom/android/org/conscrypt/TrustedCertificateStore$CertSelector;->match(Ljava/security/cert/X509Certificate;)Z
-Lcom/android/org/conscrypt/TrustedCertificateStore$PreloadHolder;-><init>()V
-Lcom/android/org/conscrypt/TrustedCertificateStore$PreloadHolder;->defaultCaCertsAddedDir:Ljava/io/File;
-Lcom/android/org/conscrypt/TrustedCertificateStore$PreloadHolder;->defaultCaCertsDeletedDir:Ljava/io/File;
-Lcom/android/org/conscrypt/TrustedCertificateStore$PreloadHolder;->defaultCaCertsSystemDir:Ljava/io/File;
-Lcom/android/org/conscrypt/TrustedCertificateStore;-><init>(Ljava/io/File;Ljava/io/File;Ljava/io/File;)V
-Lcom/android/org/conscrypt/TrustedCertificateStore;->addAliases(Ljava/util/Set;Ljava/lang/String;Ljava/io/File;)V
-Lcom/android/org/conscrypt/TrustedCertificateStore;->addedDir:Ljava/io/File;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->aliases()Ljava/util/Set;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->allSystemAliases()Ljava/util/Set;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->CERT_FACTORY:Ljava/security/cert/CertificateFactory;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->containsAlias(Ljava/lang/String;)Z
-Lcom/android/org/conscrypt/TrustedCertificateStore;->containsAlias(Ljava/lang/String;Z)Z
-Lcom/android/org/conscrypt/TrustedCertificateStore;->convertToOpenSSLIfNeeded(Ljava/security/cert/X509Certificate;)Lcom/android/org/conscrypt/OpenSSLX509Certificate;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->deleteCertificateEntry(Ljava/lang/String;)V
-Lcom/android/org/conscrypt/TrustedCertificateStore;->deletedDir:Ljava/io/File;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->file(Ljava/io/File;Ljava/lang/String;I)Ljava/io/File;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->fileForAlias(Ljava/lang/String;)Ljava/io/File;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->findAllIssuers(Ljava/security/cert/X509Certificate;)Ljava/util/Set;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->findCert(Ljava/io/File;Ljavax/security/auth/x500/X500Principal;Lcom/android/org/conscrypt/TrustedCertificateStore$CertSelector;Ljava/lang/Class;)Ljava/lang/Object;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->findIssuer(Ljava/security/cert/X509Certificate;)Ljava/security/cert/X509Certificate;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->getCertificate(Ljava/lang/String;)Ljava/security/cert/Certificate;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->getCertificate(Ljava/lang/String;Z)Ljava/security/cert/Certificate;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->getCertificateAlias(Ljava/security/cert/Certificate;)Ljava/lang/String;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->getCertificateAlias(Ljava/security/cert/Certificate;Z)Ljava/lang/String;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->getCertificateFile(Ljava/io/File;Ljava/security/cert/X509Certificate;)Ljava/io/File;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->getCreationDate(Ljava/lang/String;)Ljava/util/Date;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->getTrustAnchor(Ljava/security/cert/X509Certificate;)Ljava/security/cert/X509Certificate;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->hash(Ljavax/security/auth/x500/X500Principal;)Ljava/lang/String;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->installCertificate(Ljava/security/cert/X509Certificate;)V
-Lcom/android/org/conscrypt/TrustedCertificateStore;->isDeletedSystemCertificate(Ljava/security/cert/X509Certificate;)Z
-Lcom/android/org/conscrypt/TrustedCertificateStore;->isSelfIssuedCertificate(Lcom/android/org/conscrypt/OpenSSLX509Certificate;)Z
-Lcom/android/org/conscrypt/TrustedCertificateStore;->isSystem(Ljava/lang/String;)Z
-Lcom/android/org/conscrypt/TrustedCertificateStore;->isTombstone(Ljava/io/File;)Z
-Lcom/android/org/conscrypt/TrustedCertificateStore;->isUser(Ljava/lang/String;)Z
-Lcom/android/org/conscrypt/TrustedCertificateStore;->isUserAddedCertificate(Ljava/security/cert/X509Certificate;)Z
-Lcom/android/org/conscrypt/TrustedCertificateStore;->PREFIX_SYSTEM:Ljava/lang/String;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->PREFIX_USER:Ljava/lang/String;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->readCertificate(Ljava/io/File;)Ljava/security/cert/X509Certificate;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->removeUnnecessaryTombstones(Ljava/lang/String;)V
-Lcom/android/org/conscrypt/TrustedCertificateStore;->setDefaultUserDirectory(Ljava/io/File;)V
-Lcom/android/org/conscrypt/TrustedCertificateStore;->systemDir:Ljava/io/File;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->userAliases()Ljava/util/Set;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->writeCertificate(Ljava/io/File;Ljava/security/cert/X509Certificate;)V
-Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;-><init>(ZLjava/security/cert/X509Certificate;)V
-Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->clientAuth:Z
-Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->EKU_anyExtendedKeyUsage:Ljava/lang/String;
-Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->EKU_clientAuth:Ljava/lang/String;
-Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->EKU_msSGC:Ljava/lang/String;
-Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->EKU_nsSGC:Ljava/lang/String;
-Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->EKU_OID:Ljava/lang/String;
-Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->EKU_serverAuth:Ljava/lang/String;
-Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->leaf:Ljava/security/cert/X509Certificate;
-Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->SUPPORTED_EXTENSIONS:Ljava/util/Set;
-Lcom/android/org/conscrypt/TrustManagerImpl$TrustAnchorComparator;-><init>()V
-Lcom/android/org/conscrypt/TrustManagerImpl$TrustAnchorComparator;->CERT_COMPARATOR:Lcom/android/org/conscrypt/CertificatePriorityComparator;
-Lcom/android/org/conscrypt/TrustManagerImpl$TrustAnchorComparator;->compare(Ljava/lang/Object;Ljava/lang/Object;)I
-Lcom/android/org/conscrypt/TrustManagerImpl$TrustAnchorComparator;->compare(Ljava/security/cert/TrustAnchor;Ljava/security/cert/TrustAnchor;)I
-Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;Lcom/android/org/conscrypt/CertPinManager;)V
-Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;Lcom/android/org/conscrypt/CertPinManager;Lcom/android/org/conscrypt/TrustedCertificateStore;)V
-Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;Lcom/android/org/conscrypt/CertPinManager;Lcom/android/org/conscrypt/TrustedCertificateStore;Lcom/android/org/conscrypt/CertBlacklist;)V
-Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;Lcom/android/org/conscrypt/CertPinManager;Lcom/android/org/conscrypt/TrustedCertificateStore;Lcom/android/org/conscrypt/CertBlacklist;Lcom/android/org/conscrypt/ct/CTLogStore;Lcom/android/org/conscrypt/ct/CTVerifier;Lcom/android/org/conscrypt/ct/CTPolicy;)V
-Lcom/android/org/conscrypt/TrustManagerImpl;->acceptedIssuers(Ljava/security/KeyStore;)[Ljava/security/cert/X509Certificate;
-Lcom/android/org/conscrypt/TrustManagerImpl;->acceptedIssuers:[Ljava/security/cert/X509Certificate;
-Lcom/android/org/conscrypt/TrustManagerImpl;->blacklist:Lcom/android/org/conscrypt/CertBlacklist;
-Lcom/android/org/conscrypt/TrustManagerImpl;->checkBlacklist(Ljava/security/cert/X509Certificate;)V
-Lcom/android/org/conscrypt/TrustManagerImpl;->checkClientTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;
-Lcom/android/org/conscrypt/TrustManagerImpl;->checkCT(Ljava/lang/String;Ljava/util/List;[B[B)V
-Lcom/android/org/conscrypt/TrustManagerImpl;->checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljavax/net/ssl/SSLSession;)Ljava/util/List;
-Lcom/android/org/conscrypt/TrustManagerImpl;->checkTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljavax/net/ssl/SSLSession;Ljavax/net/ssl/SSLParameters;Z)Ljava/util/List;
-Lcom/android/org/conscrypt/TrustManagerImpl;->checkTrusted([Ljava/security/cert/X509Certificate;[B[BLjava/lang/String;Ljava/lang/String;Z)Ljava/util/List;
-Lcom/android/org/conscrypt/TrustManagerImpl;->checkTrustedRecursive([Ljava/security/cert/X509Certificate;[B[BLjava/lang/String;ZLjava/util/ArrayList;Ljava/util/ArrayList;Ljava/util/Set;)Ljava/util/List;
-Lcom/android/org/conscrypt/TrustManagerImpl;->ctEnabledOverride:Z
-Lcom/android/org/conscrypt/TrustManagerImpl;->ctPolicy:Lcom/android/org/conscrypt/ct/CTPolicy;
-Lcom/android/org/conscrypt/TrustManagerImpl;->ctVerifier:Lcom/android/org/conscrypt/ct/CTVerifier;
-Lcom/android/org/conscrypt/TrustManagerImpl;->err:Ljava/lang/Exception;
-Lcom/android/org/conscrypt/TrustManagerImpl;->factory:Ljava/security/cert/CertificateFactory;
-Lcom/android/org/conscrypt/TrustManagerImpl;->findAllTrustAnchorsByIssuerAndSignature(Ljava/security/cert/X509Certificate;)Ljava/util/Set;
-Lcom/android/org/conscrypt/TrustManagerImpl;->findTrustAnchorBySubjectAndPublicKey(Ljava/security/cert/X509Certificate;)Ljava/security/cert/TrustAnchor;
-Lcom/android/org/conscrypt/TrustManagerImpl;->getHandshakeSessionOrThrow(Ljavax/net/ssl/SSLSocket;)Ljavax/net/ssl/SSLSession;
-Lcom/android/org/conscrypt/TrustManagerImpl;->getOcspDataFromSession(Ljavax/net/ssl/SSLSession;)[B
-Lcom/android/org/conscrypt/TrustManagerImpl;->getTlsSctDataFromSession(Ljavax/net/ssl/SSLSession;)[B
-Lcom/android/org/conscrypt/TrustManagerImpl;->getTrustedChainForServer([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/net/Socket;)Ljava/util/List;
-Lcom/android/org/conscrypt/TrustManagerImpl;->getTrustedChainForServer([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljavax/net/ssl/SSLEngine;)Ljava/util/List;
-Lcom/android/org/conscrypt/TrustManagerImpl;->handleTrustStorageUpdate()V
-Lcom/android/org/conscrypt/TrustManagerImpl;->intermediateIndex:Lcom/android/org/conscrypt/TrustedCertificateIndex;
-Lcom/android/org/conscrypt/TrustManagerImpl;->isUserAddedCertificate(Ljava/security/cert/X509Certificate;)Z
-Lcom/android/org/conscrypt/TrustManagerImpl;->pinManager:Lcom/android/org/conscrypt/CertPinManager;
-Lcom/android/org/conscrypt/TrustManagerImpl;->rootKeyStore:Ljava/security/KeyStore;
-Lcom/android/org/conscrypt/TrustManagerImpl;->setCTEnabledOverride(Z)V
-Lcom/android/org/conscrypt/TrustManagerImpl;->setCTPolicy(Lcom/android/org/conscrypt/ct/CTPolicy;)V
-Lcom/android/org/conscrypt/TrustManagerImpl;->setCTVerifier(Lcom/android/org/conscrypt/ct/CTVerifier;)V
-Lcom/android/org/conscrypt/TrustManagerImpl;->setOcspResponses(Ljava/security/cert/PKIXParameters;Ljava/security/cert/X509Certificate;[B)V
-Lcom/android/org/conscrypt/TrustManagerImpl;->sortPotentialAnchors(Ljava/util/Set;)Ljava/util/Collection;
-Lcom/android/org/conscrypt/TrustManagerImpl;->trustAnchors([Ljava/security/cert/X509Certificate;)Ljava/util/Set;
-Lcom/android/org/conscrypt/TrustManagerImpl;->trustedCertificateIndex:Lcom/android/org/conscrypt/TrustedCertificateIndex;
-Lcom/android/org/conscrypt/TrustManagerImpl;->trustedCertificateStore:Lcom/android/org/conscrypt/TrustedCertificateStore;
-Lcom/android/org/conscrypt/TrustManagerImpl;->TRUST_ANCHOR_COMPARATOR:Lcom/android/org/conscrypt/TrustManagerImpl$TrustAnchorComparator;
-Lcom/android/org/conscrypt/TrustManagerImpl;->validator:Ljava/security/cert/CertPathValidator;
-Lcom/android/org/conscrypt/TrustManagerImpl;->verifyChain(Ljava/util/List;Ljava/util/List;Ljava/lang/String;Z[B[B)Ljava/util/List;
Lorg/apache/http/conn/ssl/AbstractVerifier;->IPV4_PATTERN:Ljava/util/regex/Pattern;
Lorg/apache/http/conn/ssl/AbstractVerifier;->isIPv4Address(Ljava/lang/String;)Z
Lorg/apache/http/conn/ssl/SSLSocketFactory$NoPreloadHolder;-><init>()V
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index f23966e..7072bbe 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -4930,10 +4930,6 @@
field @Deprecated public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation";
}
- public final class LocationDeviceConfig {
- field public static final String IGNORE_SETTINGS_ALLOWLIST = "ignore_settings_allowlist";
- }
-
public class LocationManager {
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void addProviderRequestChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.provider.ProviderRequest.ChangedListener);
method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
@@ -4946,7 +4942,6 @@
method public boolean isLocationEnabledForUser(@NonNull android.os.UserHandle);
method public boolean isProviderEnabledForUser(@NonNull String, @NonNull android.os.UserHandle);
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@NonNull String);
- method @Deprecated @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String);
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String, @Nullable String);
method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.UPDATE_APP_OPS_STATS}) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
@@ -12843,7 +12838,6 @@
method public void onCreated(@NonNull android.telephony.ims.stub.SipDelegate, @Nullable java.util.Set<android.telephony.ims.FeatureTagState>);
method public void onDestroyed(int);
method public void onFeatureTagRegistrationChanged(@NonNull android.telephony.ims.DelegateRegistrationState);
- method @Deprecated public void onImsConfigurationChanged(@NonNull android.telephony.ims.SipDelegateImsConfiguration);
}
public final class FeatureTagState implements android.os.Parcelable {
@@ -13664,67 +13658,6 @@
method public void sendMessage(@NonNull android.telephony.ims.SipMessage, long);
}
- @Deprecated public final class SipDelegateImsConfiguration implements android.os.Parcelable {
- method @Deprecated public boolean containsKey(@NonNull String);
- method @Deprecated @NonNull public android.os.PersistableBundle copyBundle();
- method @Deprecated public int describeContents();
- method @Deprecated public boolean getBoolean(@NonNull String, boolean);
- method @Deprecated public int getInt(@NonNull String, int);
- method @Deprecated @Nullable public String getString(@NonNull String);
- method @Deprecated public long getVersion();
- method @Deprecated public void writeToParcel(@NonNull android.os.Parcel, int);
- field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.SipDelegateImsConfiguration> CREATOR;
- field @Deprecated public static final String IPTYPE_IPV4 = "IPV4";
- field @Deprecated public static final String IPTYPE_IPV6 = "IPV6";
- field @Deprecated public static final String KEY_SIP_CONFIG_AUTHENTICATION_HEADER_STRING = "sip_config_auhentication_header_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_AUTHENTICATION_NONCE_STRING = "sip_config_authentication_nonce_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_CELLULAR_NETWORK_INFO_HEADER_STRING = "sip_config_cellular_network_info_header_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_HOME_DOMAIN_STRING = "sip_config_home_domain_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_IMEI_STRING = "sip_config_imei_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_IPTYPE_STRING = "sip_config_iptype_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_IS_COMPACT_FORM_ENABLED_BOOL = "sip_config_is_compact_form_enabled_bool";
- field @Deprecated public static final String KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL = "sip_config_is_gruu_enabled_bool";
- field @Deprecated public static final String KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL = "sip_config_is_ipsec_enabled_bool";
- field @Deprecated public static final String KEY_SIP_CONFIG_IS_KEEPALIVE_ENABLED_BOOL = "sip_config_is_keepalive_enabled_bool";
- field @Deprecated public static final String KEY_SIP_CONFIG_IS_NAT_ENABLED_BOOL = "sip_config_is_nat_enabled_bool";
- field @Deprecated public static final String KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT = "sip_config_udp_max_payload_size_int";
- field @Deprecated public static final String KEY_SIP_CONFIG_PATH_HEADER_STRING = "sip_config_path_header_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_P_ACCESS_NETWORK_INFO_HEADER_STRING = "sip_config_p_access_network_info_header_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_P_ASSOCIATED_URI_HEADER_STRING = "sip_config_p_associated_uri_header_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_P_LAST_ACCESS_NETWORK_INFO_HEADER_STRING = "sip_config_p_last_access_network_info_header_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_SECURITY_VERIFY_HEADER_STRING = "sip_config_security_verify_header_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_SERVER_DEFAULT_IPADDRESS_STRING = "sip_config_server_default_ipaddress_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_SERVER_DEFAULT_PORT_INT = "sip_config_server_default_port_int";
- field @Deprecated public static final String KEY_SIP_CONFIG_SERVER_IPSEC_CLIENT_PORT_INT = "sip_config_server_ipsec_client_port_int";
- field @Deprecated public static final String KEY_SIP_CONFIG_SERVER_IPSEC_OLD_CLIENT_PORT_INT = "sip_config_server_ipsec_old_client_port_int";
- field @Deprecated public static final String KEY_SIP_CONFIG_SERVER_IPSEC_SERVER_PORT_INT = "sip_config_server_ipsec_server_port_int";
- field @Deprecated public static final String KEY_SIP_CONFIG_SERVICE_ROUTE_HEADER_STRING = "sip_config_service_route_header_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_TRANSPORT_TYPE_STRING = "sip_config_protocol_type_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_UE_DEFAULT_IPADDRESS_STRING = "sip_config_ue_default_ipaddress_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_UE_DEFAULT_PORT_INT = "sip_config_ue_default_port_int";
- field @Deprecated public static final String KEY_SIP_CONFIG_UE_IPSEC_CLIENT_PORT_INT = "sip_config_ue_ipsec_client_port_int";
- field @Deprecated public static final String KEY_SIP_CONFIG_UE_IPSEC_OLD_CLIENT_PORT_INT = "sip_config_ue_ipsec_old_client_port_int";
- field @Deprecated public static final String KEY_SIP_CONFIG_UE_IPSEC_SERVER_PORT_INT = "sip_config_ue_ipsec_server_port_int";
- field @Deprecated public static final String KEY_SIP_CONFIG_UE_PRIVATE_USER_ID_STRING = "sip_config_ue_private_user_id_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_UE_PUBLIC_GRUU_STRING = "sip_config_ue_public_gruu_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_UE_PUBLIC_IPADDRESS_WITH_NAT_STRING = "sip_config_ue_public_ipaddress_with_nat_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_UE_PUBLIC_PORT_WITH_NAT_INT = "sip_config_ue_public_port_with_nat_int";
- field @Deprecated public static final String KEY_SIP_CONFIG_UE_PUBLIC_USER_ID_STRING = "sip_config_ue_public_user_id_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_URI_USER_PART_STRING = "sip_config_uri_user_part_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_USER_AGENT_HEADER_STRING = "sip_config_sip_user_agent_header_string";
- field @Deprecated public static final String SIP_TRANSPORT_TCP = "TCP";
- field @Deprecated public static final String SIP_TRANSPORT_UDP = "UDP";
- }
-
- @Deprecated public static final class SipDelegateImsConfiguration.Builder {
- ctor @Deprecated public SipDelegateImsConfiguration.Builder(int);
- ctor @Deprecated public SipDelegateImsConfiguration.Builder(@NonNull android.telephony.ims.SipDelegateImsConfiguration);
- method @Deprecated @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addBoolean(@NonNull String, boolean);
- method @Deprecated @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addInt(@NonNull String, int);
- method @Deprecated @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addString(@NonNull String, @NonNull String);
- method @Deprecated @NonNull public android.telephony.ims.SipDelegateImsConfiguration build();
- }
-
public class SipDelegateManager {
method @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void createSipDelegate(@NonNull android.telephony.ims.DelegateRequest, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.stub.DelegateConnectionStateCallback, @NonNull android.telephony.ims.stub.DelegateConnectionMessageCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void destroySipDelegate(@NonNull android.telephony.ims.SipDelegateConnection, int);
@@ -13892,11 +13825,10 @@
}
public interface DelegateConnectionStateCallback {
- method public default void onConfigurationChanged(@NonNull android.telephony.ims.SipDelegateConfiguration);
+ method public void onConfigurationChanged(@NonNull android.telephony.ims.SipDelegateConfiguration);
method public void onCreated(@NonNull android.telephony.ims.SipDelegateConnection);
method public void onDestroyed(int);
method public void onFeatureTagStatusChanged(@NonNull android.telephony.ims.DelegateRegistrationState, @NonNull java.util.Set<android.telephony.ims.FeatureTagState>);
- method @Deprecated public default void onImsConfigurationChanged(@NonNull android.telephony.ims.SipDelegateImsConfiguration);
}
public class ImsCallSessionImplBase implements java.lang.AutoCloseable {
diff --git a/core/api/system-removed.txt b/core/api/system-removed.txt
index 7cf0076..9a8a493 100644
--- a/core/api/system-removed.txt
+++ b/core/api/system-removed.txt
@@ -135,6 +135,7 @@
public class LocationManager {
method @Deprecated public boolean addGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
method @Deprecated public boolean addGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String);
method @Deprecated public void removeGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
method @Deprecated public void removeGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setLocationControllerExtraPackage(String);
@@ -231,6 +232,83 @@
}
+package android.telephony.ims {
+
+ public interface DelegateStateCallback {
+ method @Deprecated public void onImsConfigurationChanged(@NonNull android.telephony.ims.SipDelegateImsConfiguration);
+ }
+
+ @Deprecated public final class SipDelegateImsConfiguration implements android.os.Parcelable {
+ method public boolean containsKey(@NonNull String);
+ method @NonNull public android.os.PersistableBundle copyBundle();
+ method public int describeContents();
+ method public boolean getBoolean(@NonNull String, boolean);
+ method public int getInt(@NonNull String, int);
+ method @Nullable public String getString(@NonNull String);
+ method public long getVersion();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.SipDelegateImsConfiguration> CREATOR;
+ field public static final String IPTYPE_IPV4 = "IPV4";
+ field public static final String IPTYPE_IPV6 = "IPV6";
+ field public static final String KEY_SIP_CONFIG_AUTHENTICATION_HEADER_STRING = "sip_config_auhentication_header_string";
+ field public static final String KEY_SIP_CONFIG_AUTHENTICATION_NONCE_STRING = "sip_config_authentication_nonce_string";
+ field public static final String KEY_SIP_CONFIG_CELLULAR_NETWORK_INFO_HEADER_STRING = "sip_config_cellular_network_info_header_string";
+ field public static final String KEY_SIP_CONFIG_HOME_DOMAIN_STRING = "sip_config_home_domain_string";
+ field public static final String KEY_SIP_CONFIG_IMEI_STRING = "sip_config_imei_string";
+ field public static final String KEY_SIP_CONFIG_IPTYPE_STRING = "sip_config_iptype_string";
+ field public static final String KEY_SIP_CONFIG_IS_COMPACT_FORM_ENABLED_BOOL = "sip_config_is_compact_form_enabled_bool";
+ field public static final String KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL = "sip_config_is_gruu_enabled_bool";
+ field public static final String KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL = "sip_config_is_ipsec_enabled_bool";
+ field public static final String KEY_SIP_CONFIG_IS_KEEPALIVE_ENABLED_BOOL = "sip_config_is_keepalive_enabled_bool";
+ field public static final String KEY_SIP_CONFIG_IS_NAT_ENABLED_BOOL = "sip_config_is_nat_enabled_bool";
+ field public static final String KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT = "sip_config_udp_max_payload_size_int";
+ field public static final String KEY_SIP_CONFIG_PATH_HEADER_STRING = "sip_config_path_header_string";
+ field public static final String KEY_SIP_CONFIG_P_ACCESS_NETWORK_INFO_HEADER_STRING = "sip_config_p_access_network_info_header_string";
+ field public static final String KEY_SIP_CONFIG_P_ASSOCIATED_URI_HEADER_STRING = "sip_config_p_associated_uri_header_string";
+ field public static final String KEY_SIP_CONFIG_P_LAST_ACCESS_NETWORK_INFO_HEADER_STRING = "sip_config_p_last_access_network_info_header_string";
+ field public static final String KEY_SIP_CONFIG_SECURITY_VERIFY_HEADER_STRING = "sip_config_security_verify_header_string";
+ field public static final String KEY_SIP_CONFIG_SERVER_DEFAULT_IPADDRESS_STRING = "sip_config_server_default_ipaddress_string";
+ field public static final String KEY_SIP_CONFIG_SERVER_DEFAULT_PORT_INT = "sip_config_server_default_port_int";
+ field public static final String KEY_SIP_CONFIG_SERVER_IPSEC_CLIENT_PORT_INT = "sip_config_server_ipsec_client_port_int";
+ field public static final String KEY_SIP_CONFIG_SERVER_IPSEC_OLD_CLIENT_PORT_INT = "sip_config_server_ipsec_old_client_port_int";
+ field public static final String KEY_SIP_CONFIG_SERVER_IPSEC_SERVER_PORT_INT = "sip_config_server_ipsec_server_port_int";
+ field public static final String KEY_SIP_CONFIG_SERVICE_ROUTE_HEADER_STRING = "sip_config_service_route_header_string";
+ field public static final String KEY_SIP_CONFIG_TRANSPORT_TYPE_STRING = "sip_config_protocol_type_string";
+ field public static final String KEY_SIP_CONFIG_UE_DEFAULT_IPADDRESS_STRING = "sip_config_ue_default_ipaddress_string";
+ field public static final String KEY_SIP_CONFIG_UE_DEFAULT_PORT_INT = "sip_config_ue_default_port_int";
+ field public static final String KEY_SIP_CONFIG_UE_IPSEC_CLIENT_PORT_INT = "sip_config_ue_ipsec_client_port_int";
+ field public static final String KEY_SIP_CONFIG_UE_IPSEC_OLD_CLIENT_PORT_INT = "sip_config_ue_ipsec_old_client_port_int";
+ field public static final String KEY_SIP_CONFIG_UE_IPSEC_SERVER_PORT_INT = "sip_config_ue_ipsec_server_port_int";
+ field public static final String KEY_SIP_CONFIG_UE_PRIVATE_USER_ID_STRING = "sip_config_ue_private_user_id_string";
+ field public static final String KEY_SIP_CONFIG_UE_PUBLIC_GRUU_STRING = "sip_config_ue_public_gruu_string";
+ field public static final String KEY_SIP_CONFIG_UE_PUBLIC_IPADDRESS_WITH_NAT_STRING = "sip_config_ue_public_ipaddress_with_nat_string";
+ field public static final String KEY_SIP_CONFIG_UE_PUBLIC_PORT_WITH_NAT_INT = "sip_config_ue_public_port_with_nat_int";
+ field public static final String KEY_SIP_CONFIG_UE_PUBLIC_USER_ID_STRING = "sip_config_ue_public_user_id_string";
+ field public static final String KEY_SIP_CONFIG_URI_USER_PART_STRING = "sip_config_uri_user_part_string";
+ field public static final String KEY_SIP_CONFIG_USER_AGENT_HEADER_STRING = "sip_config_sip_user_agent_header_string";
+ field public static final String SIP_TRANSPORT_TCP = "TCP";
+ field public static final String SIP_TRANSPORT_UDP = "UDP";
+ }
+
+ public static final class SipDelegateImsConfiguration.Builder {
+ ctor public SipDelegateImsConfiguration.Builder(int);
+ ctor public SipDelegateImsConfiguration.Builder(@NonNull android.telephony.ims.SipDelegateImsConfiguration);
+ method @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addBoolean(@NonNull String, boolean);
+ method @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addInt(@NonNull String, int);
+ method @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addString(@NonNull String, @NonNull String);
+ method @NonNull public android.telephony.ims.SipDelegateImsConfiguration build();
+ }
+
+}
+
+package android.telephony.ims.stub {
+
+ public interface DelegateConnectionStateCallback {
+ method @Deprecated public default void onImsConfigurationChanged(@NonNull android.telephony.ims.SipDelegateImsConfiguration);
+ }
+
+}
+
package android.view.translation {
public final class UiTranslationManager {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 8499b37..2f795f0 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1360,10 +1360,6 @@
method public void setType(int);
}
- public final class LocationDeviceConfig {
- field public static final String IGNORE_SETTINGS_ALLOWLIST = "ignore_settings_allowlist";
- }
-
public class LocationManager {
method @NonNull public String[] getBackgroundThrottlingWhitelist();
method @NonNull public android.os.PackageTagsList getIgnoreSettingsAllowlist();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index eb0a7b4..7149096 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -237,7 +237,6 @@
import java.util.TimeZone;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
/**
@@ -338,6 +337,11 @@
*/
@UnsupportedAppUsage
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
+ /**
+ * Maps from activity token to local record of the activities that are preparing to be launched.
+ */
+ final Map<IBinder, ActivityClientRecord> mLaunchingActivities =
+ Collections.synchronizedMap(new ArrayMap<IBinder, ActivityClientRecord>());
/** The activities to be truly destroyed (not include relaunch). */
final Map<IBinder, ClientTransactionItem> mActivitiesToBeDestroyed =
Collections.synchronizedMap(new ArrayMap<IBinder, ClientTransactionItem>());
@@ -347,7 +351,6 @@
// Number of activities that are currently visible on-screen.
@UnsupportedAppUsage
int mNumVisibleActivities = 0;
- private final AtomicInteger mNumLaunchingActivities = new AtomicInteger();
@GuardedBy("mAppThread")
private int mLastProcessState = PROCESS_STATE_UNKNOWN;
@GuardedBy("mAppThread")
@@ -1182,7 +1185,7 @@
InetAddress.clearDnsCache();
// Allow libcore to perform the necessary actions as it sees fit upon a network
// configuration change.
- NetworkEventDispatcher.getInstance().onNetworkConfigurationChanged();
+ NetworkEventDispatcher.getInstance().dispatchNetworkConfigurationChange();
}
public void updateHttpProxy() {
@@ -3256,6 +3259,21 @@
}
@Override
+ public void addLaunchingActivity(IBinder token, ActivityClientRecord activity) {
+ mLaunchingActivities.put(token, activity);
+ }
+
+ @Override
+ public ActivityClientRecord getLaunchingActivity(IBinder token) {
+ return mLaunchingActivities.get(token);
+ }
+
+ @Override
+ public void removeLaunchingActivity(IBinder token) {
+ mLaunchingActivities.remove(token);
+ }
+
+ @Override
public ActivityClientRecord getActivityClient(IBinder token) {
return mActivities.get(token);
}
@@ -3299,7 +3317,7 @@
// Defer the top state for VM to avoid aggressive JIT compilation affecting activity
// launch time.
if (processState == ActivityManager.PROCESS_STATE_TOP
- && mNumLaunchingActivities.get() > 0) {
+ && !mLaunchingActivities.isEmpty()) {
mPendingProcessState = processState;
mH.postDelayed(this::applyPendingProcessState, PENDING_TOP_PROCESS_STATE_TIMEOUT);
} else {
@@ -3315,7 +3333,7 @@
// Handle the pending configuration if the process state is changed from cached to
// non-cached. Except the case where there is a launching activity because the
// LaunchActivityItem will handle it.
- if (wasCached && !isCachedProcessState() && mNumLaunchingActivities.get() == 0) {
+ if (wasCached && !isCachedProcessState() && mLaunchingActivities.isEmpty()) {
final Configuration pendingConfig =
mConfigurationController.getPendingConfiguration(false /* clearPending */);
if (pendingConfig == null) {
@@ -3353,11 +3371,6 @@
}
}
- @Override
- public void countLaunchingActivities(int num) {
- mNumLaunchingActivities.getAndAdd(num);
- }
-
@UnsupportedAppUsage
public final void sendActivityResult(
IBinder token, String id, int requestCode,
@@ -6413,7 +6426,7 @@
VMDebug.setAllocTrackerStackDepth(Integer.parseInt(property));
}
if (data.trackAllocation) {
- DdmVmInternal.enableRecentAllocations(true);
+ DdmVmInternal.setRecentAllocationsTrackingEnabled(true);
}
// Note when this process has started.
Process.setStartTimes(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index c752f34..115101c 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -82,9 +82,6 @@
/** Set current process state. */
public abstract void updateProcessState(int processState, boolean fromIpc);
- /** Count how many activities are launching. */
- public abstract void countLaunchingActivities(int num);
-
// Execute phase related logic and handlers. Methods here execute actual lifecycle transactions
// and deliver callbacks.
@@ -193,6 +190,26 @@
FixedRotationAdjustments fixedRotationAdjustments);
/**
+ * Add {@link ActivityClientRecord} that is preparing to be launched.
+ * @param token Activity token.
+ * @param activity An initialized instance of {@link ActivityClientRecord} to use during launch.
+ */
+ public abstract void addLaunchingActivity(IBinder token, ActivityClientRecord activity);
+
+ /**
+ * Get {@link ActivityClientRecord} that is preparing to be launched.
+ * @param token Activity token.
+ * @return An initialized instance of {@link ActivityClientRecord} to use during launch.
+ */
+ public abstract ActivityClientRecord getLaunchingActivity(IBinder token);
+
+ /**
+ * Remove {@link ActivityClientRecord} from the launching activity list.
+ * @param token Activity token.
+ */
+ public abstract void removeLaunchingActivity(IBinder token);
+
+ /**
* Get {@link android.app.ActivityThread.ActivityClientRecord} instance that corresponds to the
* provided token.
*/
diff --git a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
index d5585db..032b57e 100644
--- a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
+++ b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
@@ -40,7 +40,8 @@
@Override
public void preExecute(android.app.ClientTransactionHandler client, IBinder token) {
- final ActivityClientRecord r = getActivityClientRecord(client, token);
+ final ActivityClientRecord r = getActivityClientRecord(client, token,
+ true /* includeLaunching */);
// Notify the client of an upcoming change in the token configuration. This ensures that
// batches of config change items only process the newest configuration.
client.updatePendingActivityConfiguration(r, mConfiguration);
diff --git a/core/java/android/app/servertransaction/ActivityTransactionItem.java b/core/java/android/app/servertransaction/ActivityTransactionItem.java
index f7d7e9d..a539812 100644
--- a/core/java/android/app/servertransaction/ActivityTransactionItem.java
+++ b/core/java/android/app/servertransaction/ActivityTransactionItem.java
@@ -55,15 +55,40 @@
@NonNull ActivityClientRecord getActivityClientRecord(
@NonNull ClientTransactionHandler client, IBinder token) {
- final ActivityClientRecord r = client.getActivityClient(token);
+ return getActivityClientRecord(client, token, false /* includeLaunching */);
+ }
+
+ /**
+ * Get the {@link ActivityClientRecord} instance that corresponds to the provided token.
+ * @param client Target client handler.
+ * @param token Target activity token.
+ * @param includeLaunching Indicate to also find the {@link ActivityClientRecord} in launching
+ * activity list. It should be noted that there is no activity in
+ * {@link ActivityClientRecord} from the launching activity list.
+ * @return The {@link ActivityClientRecord} instance that corresponds to the provided token.
+ */
+ @NonNull ActivityClientRecord getActivityClientRecord(
+ @NonNull ClientTransactionHandler client, IBinder token, boolean includeLaunching) {
+ ActivityClientRecord r = client.getActivityClient(token);
+ if (r != null) {
+ if (client.getActivity(token) == null) {
+ throw new IllegalArgumentException("Activity must not be null to execute "
+ + "transaction item");
+ }
+ return r;
+ }
+ // The activity may not be launched yet. Fallback to check launching activity.
+ if (includeLaunching) {
+ r = client.getLaunchingActivity(token);
+ }
if (r == null) {
throw new IllegalArgumentException("Activity client record must not be null to execute "
+ "transaction item");
}
- if (client.getActivity(token) == null) {
- throw new IllegalArgumentException("Activity must not be null to execute "
- + "transaction item");
- }
+
+ // We don't need to check the activity of launching activity client records because they
+ // have not been launched yet.
+
return r;
}
}
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index e281a02..34e4fcd 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -82,7 +82,12 @@
@Override
public void preExecute(ClientTransactionHandler client, IBinder token) {
- client.countLaunchingActivities(1);
+ ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
+ mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
+ mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
+ client, mAssistToken, mFixedRotationAdjustments, mShareableActivityToken,
+ mLaunchedFromBubble);
+ client.addLaunchingActivity(token, r);
client.updateProcessState(mProcState, false);
client.updatePendingConfiguration(mCurConfig);
if (mActivityClientController != null) {
@@ -94,11 +99,7 @@
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
- ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
- mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
- mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
- client, mAssistToken, mFixedRotationAdjustments, mShareableActivityToken,
- mLaunchedFromBubble);
+ ActivityClientRecord r = client.getLaunchingActivity(token);
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -106,7 +107,7 @@
@Override
public void postExecute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
- client.countLaunchingActivities(-1);
+ client.removeLaunchingActivity(token);
}
diff --git a/core/java/android/app/servertransaction/MoveToDisplayItem.java b/core/java/android/app/servertransaction/MoveToDisplayItem.java
index 944367e..4b8a347 100644
--- a/core/java/android/app/servertransaction/MoveToDisplayItem.java
+++ b/core/java/android/app/servertransaction/MoveToDisplayItem.java
@@ -40,7 +40,8 @@
@Override
public void preExecute(ClientTransactionHandler client, IBinder token) {
- final ActivityClientRecord r = getActivityClientRecord(client, token);
+ final ActivityClientRecord r = getActivityClientRecord(client, token,
+ true /* includeLaunching */);
// Notify the client of an upcoming change in the token configuration. This ensures that
// batches of config change items only process the newest configuration.
client.updatePendingActivityConfiguration(r, mConfiguration);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index fc676cf..886cd7f 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -400,10 +400,7 @@
public static final int BIND_BYPASS_POWER_NETWORK_RESTRICTIONS = 0x00020000;
/**
- * Flag for {@link #bindService}: allow background foreground service starts from the bound
- * service's process.
- * This flag is only respected if the caller is holding
- * {@link android.Manifest.permission#START_FOREGROUND_SERVICES_FROM_BACKGROUND}.
+ * Do not use. This flag is no longer needed nor used.
* @hide
*/
@SystemApi
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 33606e8..33a34be 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -4672,27 +4672,27 @@
@PermissionGroupInfoFlags int flags);
/**
- * Get the platform permissions which belong to a particular permission group.
+ * Get the platform-defined permissions which belong to a particular permission group.
*
- * @param permissionGroupName The permission group whose permissions are desired
- * @param executor Executor on which to invoke the callback
- * @param callback A callback which will receive a list of the platform permissions in the
- * group, or empty if the group is not a valid platform group, or there
- * was an exception.
+ * @param permissionGroupName the permission group whose permissions are desired
+ * @param executor the {@link Executor} on which to invoke the callback
+ * @param callback the callback which will receive a list of the platform-defined permissions in
+ * the group, or empty if the group is not a valid platform-defined permission
+ * group, or there was an exception
*/
public void getPlatformPermissionsForGroup(@NonNull String permissionGroupName,
@NonNull @CallbackExecutor Executor executor,
@NonNull Consumer<List<String>> callback) {}
/**
- * Get the platform group of a particular permission, if the permission is a platform
- * permission.
+ * Get the platform-defined permission group of a particular permission, if the permission is a
+ * platform-defined permission.
*
- * @param permissionName The permission name whose group is desired
- * @param executor Executor on which to invoke the callback
- * @param callback A callback which will receive the name of the permission group this
- * permission belongs to, or null if it has no group, is not a platform
- * permission, or there was an exception.
+ * @param permissionName the permission whose group is desired
+ * @param executor the {@link Executor} on which to invoke the callback
+ * @param callback the callback which will receive the name of the permission group this
+ * permission belongs to, or {@code null} if it has no group, is not a
+ * platform-defined permission, or there was an exception
*/
public void getGroupOfPlatformPermission(@NonNull String permissionName,
@NonNull @CallbackExecutor Executor executor, @NonNull Consumer<String> callback) {}
diff --git a/core/java/android/ddm/DdmHandle.java b/core/java/android/ddm/DdmHandle.java
new file mode 100644
index 0000000..0505fee
--- /dev/null
+++ b/core/java/android/ddm/DdmHandle.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.ddm;
+
+import org.apache.harmony.dalvik.ddmc.ChunkHandler;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Contains utility methods for chunk serialization and deserialization.
+ */
+public abstract class DdmHandle extends ChunkHandler {
+
+ /**
+ * Utility function to copy a String out of a ByteBuffer.
+ *
+ * This is here because multiple chunk handlers can make use of it,
+ * and there's nowhere better to put it.
+ */
+ public static String getString(ByteBuffer buf, int len) {
+ char[] data = new char[len];
+ for (int i = 0; i < len; i++) {
+ data[i] = buf.getChar();
+ }
+ return new String(data);
+ }
+
+ /**
+ * Utility function to copy a String into a ByteBuffer.
+ */
+ public static void putString(ByteBuffer buf, String str) {
+ int len = str.length();
+ for (int i = 0; i < len; i++) {
+ buf.putChar(str.charAt(i));
+ }
+ }
+
+}
diff --git a/core/java/android/ddm/DdmHandleAppName.java b/core/java/android/ddm/DdmHandleAppName.java
index 35da062..e19f19f 100644
--- a/core/java/android/ddm/DdmHandleAppName.java
+++ b/core/java/android/ddm/DdmHandleAppName.java
@@ -30,9 +30,9 @@
/**
* Track our app name. We don't (currently) handle any inbound packets.
*/
-public class DdmHandleAppName extends ChunkHandler {
+public class DdmHandleAppName extends DdmHandle {
- public static final int CHUNK_APNM = type("APNM");
+ public static final int CHUNK_APNM = ChunkHandler.type("APNM");
private static volatile Names sNames = new Names("", "");
@@ -51,13 +51,13 @@
* Called when the DDM server connects. The handler is allowed to
* send messages to the server.
*/
- public void connected() {}
+ public void onConnected() {}
/**
* Called when the DDM server disconnects. Can be used to disable
* periodic transmissions or clean up saved state.
*/
- public void disconnected() {}
+ public void onDisconnected() {}
/**
* Handle a chunk of data.
diff --git a/core/java/android/ddm/DdmHandleExit.java b/core/java/android/ddm/DdmHandleExit.java
index 74ae37a..a9e3d16 100644
--- a/core/java/android/ddm/DdmHandleExit.java
+++ b/core/java/android/ddm/DdmHandleExit.java
@@ -16,18 +16,20 @@
package android.ddm;
+import android.util.Log;
+
import org.apache.harmony.dalvik.ddmc.Chunk;
import org.apache.harmony.dalvik.ddmc.ChunkHandler;
import org.apache.harmony.dalvik.ddmc.DdmServer;
-import android.util.Log;
+
import java.nio.ByteBuffer;
/**
* Handle an EXIT chunk.
*/
-public class DdmHandleExit extends ChunkHandler {
+public class DdmHandleExit extends DdmHandle {
- public static final int CHUNK_EXIT = type("EXIT");
+ public static final int CHUNK_EXIT = ChunkHandler.type("EXIT");
private static DdmHandleExit mInstance = new DdmHandleExit();
@@ -46,13 +48,13 @@
* Called when the DDM server connects. The handler is allowed to
* send messages to the server.
*/
- public void connected() {}
+ public void onConnected() {}
/**
* Called when the DDM server disconnects. Can be used to disable
* periodic transmissions or clean up saved state.
*/
- public void disconnected() {}
+ public void onDisconnected() {}
/**
* Handle a chunk of data. We're only registered for "EXIT".
diff --git a/core/java/android/ddm/DdmHandleHeap.java b/core/java/android/ddm/DdmHandleHeap.java
index 8fa2352..2edb5c7 100644
--- a/core/java/android/ddm/DdmHandleHeap.java
+++ b/core/java/android/ddm/DdmHandleHeap.java
@@ -16,21 +16,18 @@
package android.ddm;
+import android.util.Log;
+
import org.apache.harmony.dalvik.ddmc.Chunk;
import org.apache.harmony.dalvik.ddmc.ChunkHandler;
import org.apache.harmony.dalvik.ddmc.DdmServer;
-import org.apache.harmony.dalvik.ddmc.DdmVmInternal;
-import android.os.Debug;
-import android.util.Log;
-import java.io.IOException;
-import java.nio.ByteBuffer;
/**
* Handle native and virtual heap requests.
*/
-public class DdmHandleHeap extends ChunkHandler {
+public class DdmHandleHeap extends DdmHandle {
- public static final int CHUNK_HPGC = type("HPGC");
+ public static final int CHUNK_HPGC = ChunkHandler.type("HPGC");
private static DdmHandleHeap mInstance = new DdmHandleHeap();
@@ -49,13 +46,13 @@
* Called when the DDM server connects. The handler is allowed to
* send messages to the server.
*/
- public void connected() {}
+ public void onConnected() {}
/**
* Called when the DDM server disconnects. Can be used to disable
* periodic transmissions or clean up saved state.
*/
- public void disconnected() {}
+ public void onDisconnected() {}
/**
* Handle a chunk of data.
@@ -68,8 +65,7 @@
if (type == CHUNK_HPGC) {
return handleHPGC(request);
} else {
- throw new RuntimeException("Unknown packet "
- + ChunkHandler.name(type));
+ throw new RuntimeException("Unknown packet " + name(type));
}
}
diff --git a/core/java/android/ddm/DdmHandleHello.java b/core/java/android/ddm/DdmHandleHello.java
index 60dfc8d..4160029 100644
--- a/core/java/android/ddm/DdmHandleHello.java
+++ b/core/java/android/ddm/DdmHandleHello.java
@@ -31,11 +31,11 @@
/**
* Handle "hello" messages and feature discovery.
*/
-public class DdmHandleHello extends ChunkHandler {
+public class DdmHandleHello extends DdmHandle {
- public static final int CHUNK_HELO = type("HELO");
- public static final int CHUNK_WAIT = type("WAIT");
- public static final int CHUNK_FEAT = type("FEAT");
+ public static final int CHUNK_HELO = ChunkHandler.type("HELO");
+ public static final int CHUNK_WAIT = ChunkHandler.type("WAIT");
+ public static final int CHUNK_FEAT = ChunkHandler.type("FEAT");
private static final int CLIENT_PROTOCOL_VERSION = 1;
@@ -61,15 +61,14 @@
* Called when the DDM server connects. The handler is allowed to
* send messages to the server.
*/
- public void connected() {
+ public void onConnected() {
if (false)
Log.v("ddm-hello", "Connected!");
if (false) {
/* test spontaneous transmission */
byte[] data = new byte[] { 0, 1, 2, 3, 4, -4, -3, -2, -1, 127 };
- Chunk testChunk =
- new Chunk(ChunkHandler.type("TEST"), data, 1, data.length-2);
+ Chunk testChunk = new Chunk(ChunkHandler.type("TEST"), data, 1, data.length - 2);
DdmServer.sendChunk(testChunk);
}
}
@@ -78,7 +77,7 @@
* Called when the DDM server disconnects. Can be used to disable
* periodic transmissions or clean up saved state.
*/
- public void disconnected() {
+ public void onDisconnected() {
if (false)
Log.v("ddm-hello", "Disconnected!");
}
@@ -96,8 +95,7 @@
} else if (type == CHUNK_FEAT) {
return handleFEAT(request);
} else {
- throw new RuntimeException("Unknown packet "
- + ChunkHandler.name(type));
+ throw new RuntimeException("Unknown packet " + name(type));
}
}
diff --git a/core/java/android/ddm/DdmHandleNativeHeap.java b/core/java/android/ddm/DdmHandleNativeHeap.java
index 775c570..dfd451c 100644
--- a/core/java/android/ddm/DdmHandleNativeHeap.java
+++ b/core/java/android/ddm/DdmHandleNativeHeap.java
@@ -16,17 +16,18 @@
package android.ddm;
+import android.util.Log;
+
import org.apache.harmony.dalvik.ddmc.Chunk;
import org.apache.harmony.dalvik.ddmc.ChunkHandler;
import org.apache.harmony.dalvik.ddmc.DdmServer;
-import android.util.Log;
/**
* Handle thread-related traffic.
*/
-public class DdmHandleNativeHeap extends ChunkHandler {
+public class DdmHandleNativeHeap extends DdmHandle {
- public static final int CHUNK_NHGT = type("NHGT");
+ public static final int CHUNK_NHGT = ChunkHandler.type("NHGT");
private static DdmHandleNativeHeap mInstance = new DdmHandleNativeHeap();
@@ -45,13 +46,13 @@
* Called when the DDM server connects. The handler is allowed to
* send messages to the server.
*/
- public void connected() {}
+ public void onConnected() {}
/**
* Called when the DDM server disconnects. Can be used to disable
* periodic transmissions or clean up saved state.
*/
- public void disconnected() {}
+ public void onDisconnected() {}
/**
* Handle a chunk of data.
@@ -63,8 +64,7 @@
if (type == CHUNK_NHGT) {
return handleNHGT(request);
} else {
- throw new RuntimeException("Unknown packet "
- + ChunkHandler.name(type));
+ throw new RuntimeException("Unknown packet " + name(type));
}
}
diff --git a/core/java/android/ddm/DdmHandleProfiling.java b/core/java/android/ddm/DdmHandleProfiling.java
index cce4dd2..806e4bd 100644
--- a/core/java/android/ddm/DdmHandleProfiling.java
+++ b/core/java/android/ddm/DdmHandleProfiling.java
@@ -16,25 +16,28 @@
package android.ddm;
+
+import android.os.Debug;
+import android.util.Log;
+
import org.apache.harmony.dalvik.ddmc.Chunk;
import org.apache.harmony.dalvik.ddmc.ChunkHandler;
import org.apache.harmony.dalvik.ddmc.DdmServer;
-import android.os.Debug;
-import android.util.Log;
+
import java.nio.ByteBuffer;
/**
* Handle profiling requests.
*/
-public class DdmHandleProfiling extends ChunkHandler {
+public class DdmHandleProfiling extends DdmHandle {
- public static final int CHUNK_MPRS = type("MPRS");
- public static final int CHUNK_MPRE = type("MPRE");
- public static final int CHUNK_MPSS = type("MPSS");
- public static final int CHUNK_MPSE = type("MPSE");
- public static final int CHUNK_MPRQ = type("MPRQ");
- public static final int CHUNK_SPSS = type("SPSS");
- public static final int CHUNK_SPSE = type("SPSE");
+ public static final int CHUNK_MPRS = ChunkHandler.type("MPRS");
+ public static final int CHUNK_MPRE = ChunkHandler.type("MPRE");
+ public static final int CHUNK_MPSS = ChunkHandler.type("MPSS");
+ public static final int CHUNK_MPSE = ChunkHandler.type("MPSE");
+ public static final int CHUNK_MPRQ = ChunkHandler.type("MPRQ");
+ public static final int CHUNK_SPSS = ChunkHandler.type("SPSS");
+ public static final int CHUNK_SPSE = ChunkHandler.type("SPSE");
private static final boolean DEBUG = false;
private static DdmHandleProfiling mInstance = new DdmHandleProfiling();
@@ -60,13 +63,13 @@
* Called when the DDM server connects. The handler is allowed to
* send messages to the server.
*/
- public void connected() {}
+ public void onConnected() {}
/**
* Called when the DDM server disconnects. Can be used to disable
* periodic transmissions or clean up saved state.
*/
- public void disconnected() {}
+ public void onDisconnected() {}
/**
* Handle a chunk of data.
@@ -91,8 +94,7 @@
} else if (type == CHUNK_SPSE) {
return handleMPSEOrSPSE(request, "Sample");
} else {
- throw new RuntimeException("Unknown packet "
- + ChunkHandler.name(type));
+ throw new RuntimeException("Unknown packet " + name(type));
}
}
diff --git a/core/java/android/ddm/DdmHandleViewDebug.java b/core/java/android/ddm/DdmHandleViewDebug.java
index 5539dc9..6b0f78f 100644
--- a/core/java/android/ddm/DdmHandleViewDebug.java
+++ b/core/java/android/ddm/DdmHandleViewDebug.java
@@ -39,12 +39,12 @@
* Handle various requests related to profiling / debugging of the view system.
* Support for these features are advertised via {@link DdmHandleHello}.
*/
-public class DdmHandleViewDebug extends ChunkHandler {
+public class DdmHandleViewDebug extends DdmHandle {
/** List {@link ViewRootImpl}'s of this process. */
- private static final int CHUNK_VULW = type("VULW");
+ private static final int CHUNK_VULW = ChunkHandler.type("VULW");
/** Operation on view root, first parameter in packet should be one of VURT_* constants */
- private static final int CHUNK_VURT = type("VURT");
+ private static final int CHUNK_VURT = ChunkHandler.type("VURT");
/** Dump view hierarchy. */
private static final int VURT_DUMP_HIERARCHY = 1;
@@ -59,7 +59,7 @@
* Generic View Operation, first parameter in the packet should be one of the
* VUOP_* constants below.
*/
- private static final int CHUNK_VUOP = type("VUOP");
+ private static final int CHUNK_VUOP = ChunkHandler.type("VUOP");
/** Capture View. */
private static final int VUOP_CAPTURE_VIEW = 1;
@@ -99,11 +99,11 @@
}
@Override
- public void connected() {
+ public void onConnected() {
}
@Override
- public void disconnected() {
+ public void onDisconnected() {
}
@Override
@@ -154,7 +154,7 @@
return createFailChunk(ERR_INVALID_OP, "Unknown view operation: " + op);
}
} else {
- throw new RuntimeException("Unknown packet " + ChunkHandler.name(type));
+ throw new RuntimeException("Unknown packet " + name(type));
}
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index f0d410f..881e0cf 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -481,6 +481,7 @@
boolean mFullscreenApplied;
boolean mIsFullscreen;
+ private boolean mLastWasInFullscreenMode;
@UnsupportedAppUsage
View mExtractView;
boolean mExtractViewHidden;
@@ -920,8 +921,17 @@
if (mHandler == null) {
mHandler = new Handler(getMainLooper());
}
- mImeSurfaceScheduledForRemoval = true;
- mHandler.postDelayed(() -> removeImeSurface(), TIMEOUT_SURFACE_REMOVAL_MILLIS);
+
+ if (mLastWasInFullscreenMode) {
+ // Caching surface / delaying surface removal can cause mServedView to detach in certain
+ // cases in RecyclerView (b/187772544).
+ // TODO(b/188818557): Re-enable IME surface caching for fullscreen mode once detaching
+ // view issues is resolved in RecyclerView.
+ removeImeSurface();
+ } else {
+ mImeSurfaceScheduledForRemoval = true;
+ mHandler.postDelayed(() -> removeImeSurface(), TIMEOUT_SURFACE_REMOVAL_MILLIS);
+ }
}
private void removeImeSurface() {
@@ -2350,6 +2360,7 @@
onWindowHidden();
mDecorViewWasVisible = false;
}
+ mLastWasInFullscreenMode = mIsFullscreen;
updateFullscreenMode();
}
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index 370052d..f2857ce 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -368,27 +368,19 @@
};
/** Returns a proto (as used for atoms.proto) corresponding to this BatteryUsageStats. */
- public byte[] getStatsProto(long sessionEndTimestampMs) {
-
- final long sessionStartMillis = getStatsStartTimestamp();
- // TODO(b/187223764): Use the getStatsEndTimestamp() instead, once that is added.
- final long sessionEndMillis = sessionEndTimestampMs;
- final long sessionDurationMillis = sessionEndTimestampMs - getStatsStartTimestamp();
-
+ public byte[] getStatsProto() {
final BatteryConsumer deviceBatteryConsumer = getAggregateBatteryConsumer(
AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE);
- final int sessionDischargePercentage = getDischargePercentage();
-
final ProtoOutputStream proto = new ProtoOutputStream();
- proto.write(BatteryUsageStatsAtomsProto.SESSION_START_MILLIS, sessionStartMillis);
- proto.write(BatteryUsageStatsAtomsProto.SESSION_END_MILLIS, sessionEndMillis);
- proto.write(BatteryUsageStatsAtomsProto.SESSION_DURATION_MILLIS, sessionDurationMillis);
+ proto.write(BatteryUsageStatsAtomsProto.SESSION_START_MILLIS, getStatsStartTimestamp());
+ proto.write(BatteryUsageStatsAtomsProto.SESSION_END_MILLIS, getStatsEndTimestamp());
+ proto.write(BatteryUsageStatsAtomsProto.SESSION_DURATION_MILLIS, getStatsDuration());
deviceBatteryConsumer.writeStatsProto(proto,
BatteryUsageStatsAtomsProto.DEVICE_BATTERY_CONSUMER);
writeUidBatteryConsumersProto(proto);
proto.write(BatteryUsageStatsAtomsProto.SESSION_DISCHARGE_PERCENTAGE,
- sessionDischargePercentage);
+ getDischargePercentage());
return proto.getBytes();
}
@@ -399,8 +391,8 @@
private void writeUidBatteryConsumersProto(ProtoOutputStream proto) {
final List<UidBatteryConsumer> consumers = getUidBatteryConsumers();
- // TODO: Sort the list by power consumption. If during the for, proto.getRawSize() > 45kb,
- // truncate the remainder of the list.
+ // TODO(b/189225426): Sort the list by power consumption. If during the for,
+ // proto.getRawSize() > 45kb, truncate the remainder of the list.
final int size = consumers.size();
for (int i = 0; i < size; i++) {
final UidBatteryConsumer consumer = consumers.get(i);
diff --git a/core/java/android/os/HidlMemory.java b/core/java/android/os/HidlMemory.java
index 26fc6f0..2539a6b 100644
--- a/core/java/android/os/HidlMemory.java
+++ b/core/java/android/os/HidlMemory.java
@@ -79,6 +79,7 @@
public void close() throws IOException {
if (mHandle != null) {
mHandle.close();
+ mHandle = null;
}
}
diff --git a/core/java/android/os/VibratorManager.java b/core/java/android/os/VibratorManager.java
index 01cece3..c82a516 100644
--- a/core/java/android/os/VibratorManager.java
+++ b/core/java/android/os/VibratorManager.java
@@ -94,6 +94,8 @@
* VibrationEffect VibrationEffects} to be played on one or more vibrators.
* </p>
*
+ * <p>The app should be in foreground for the vibration to happen.</p>
+ *
* @param effect a combination of effects to be performed by one or more vibrators.
*/
@RequiresPermission(android.Manifest.permission.VIBRATE)
@@ -109,6 +111,9 @@
* VibrationEffect} to be played on one or more vibrators.
* </p>
*
+ * <p>The app should be in foreground for the vibration to happen. Background apps should
+ * specify a ringtone, notification or alarm usage in order to vibrate.</p>
+ *
* @param effect a combination of effects to be performed by one or more vibrators.
* @param attributes {@link VibrationAttributes} corresponding to the vibration. For example,
* specify {@link VibrationAttributes#USAGE_ALARM} for alarm vibrations or
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0acacb6..908d236 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9828,30 +9828,37 @@
if (mContext.getContentCaptureOptions() == null) return;
if (appeared) {
- if (!isLaidOut() || getVisibility() != VISIBLE
- || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) {
+ // The appeared event stops sending to AiAi.
+ // 1. The view is hidden.
+ // 2. The same event was sent.
+ // 3. The view is not laid out, and it will be laid out in the future.
+ // Some recycled views cached its layout and a relayout is unnecessary. In this case,
+ // system still needs to notify content capture the view appeared. When a view is
+ // recycled, it will set the flag PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED.
+ final boolean isRecycledWithoutRelayout = getNotifiedContentCaptureDisappeared()
+ && getVisibility() == VISIBLE
+ && !isLayoutRequested();
+ if (getVisibility() != VISIBLE || getNotifiedContentCaptureAppeared()
+ || !(isLaidOut() || isRecycledWithoutRelayout)) {
if (DEBUG_CONTENT_CAPTURE) {
Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'appeared' on " + this + ": laid="
+ isLaidOut() + ", visibleToUser=" + isVisibleToUser()
+ ", visible=" + (getVisibility() == VISIBLE)
- + ": alreadyNotifiedAppeared=" + ((mPrivateFlags4
- & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0)
- + ", alreadyNotifiedDisappeared=" + ((mPrivateFlags4
- & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0));
+ + ": alreadyNotifiedAppeared=" + getNotifiedContentCaptureAppeared()
+ + ", alreadyNotifiedDisappeared="
+ + getNotifiedContentCaptureDisappeared());
}
return;
}
} else {
- if ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) == 0
- || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0) {
+ if (!getNotifiedContentCaptureAppeared() || getNotifiedContentCaptureDisappeared()) {
if (DEBUG_CONTENT_CAPTURE) {
Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'disappeared' on " + this + ": laid="
+ isLaidOut() + ", visibleToUser=" + isVisibleToUser()
+ ", visible=" + (getVisibility() == VISIBLE)
- + ": alreadyNotifiedAppeared=" + ((mPrivateFlags4
- & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0)
- + ", alreadyNotifiedDisappeared=" + ((mPrivateFlags4
- & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0));
+ + ": alreadyNotifiedAppeared=" + getNotifiedContentCaptureAppeared()
+ + ", alreadyNotifiedDisappeared="
+ + getNotifiedContentCaptureDisappeared());
}
return;
}
@@ -9899,6 +9906,10 @@
}
+ private boolean getNotifiedContentCaptureDisappeared() {
+ return (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0;
+ }
+
/**
* Sets the (optional) {@link ContentCaptureSession} associated with this view.
*
diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java
index 0d041c4..e693d9d 100644
--- a/core/java/com/android/internal/os/CpuPowerCalculator.java
+++ b/core/java/com/android/internal/os/CpuPowerCalculator.java
@@ -201,7 +201,10 @@
result.packageWithHighestDrain = packageWithHighestDrain;
}
- private double calculateUidModeledPowerMah(BatteryStats.Uid u, int statsType) {
+ /**
+ * Calculates CPU power consumed by the specified app, using the PowerProfile model.
+ */
+ public double calculateUidModeledPowerMah(BatteryStats.Uid u, int statsType) {
// Constant battery drain when CPU is active
double powerMah = calculateActiveCpuPowerMah(u.getCpuActiveTime());
diff --git a/core/java/com/android/internal/os/SystemServicePowerCalculator.java b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
index a26abc2..b4a2b63 100644
--- a/core/java/com/android/internal/os/SystemServicePowerCalculator.java
+++ b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
@@ -40,8 +40,10 @@
// to this layout:
// {cluster1-speed1, cluster1-speed2, ..., cluster2-speed1, cluster2-speed2, ...}
private final UsageBasedPowerEstimator[] mPowerEstimators;
+ private final CpuPowerCalculator mCpuPowerCalculator;
public SystemServicePowerCalculator(PowerProfile powerProfile) {
+ mCpuPowerCalculator = new CpuPowerCalculator(powerProfile);
int numFreqs = 0;
final int numCpuClusters = powerProfile.getNumCpuClusters();
for (int cluster = 0; cluster < numCpuClusters; cluster++) {
@@ -62,7 +64,22 @@
@Override
public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
- double systemServicePowerMah = calculateSystemServicePower(batteryStats);
+ final BatteryStats.Uid systemUid = batteryStats.getUidStats().get(Process.SYSTEM_UID);
+ if (systemUid == null) {
+ return;
+ }
+
+ final long consumptionUC = systemUid.getCpuMeasuredBatteryConsumptionUC();
+ final int powerModel = getPowerModel(consumptionUC, query);
+
+ double systemServicePowerMah;
+ if (powerModel == BatteryConsumer.POWER_MODEL_MEASURED_ENERGY) {
+ systemServicePowerMah = calculatePowerUsingMeasuredConsumption(batteryStats,
+ systemUid, consumptionUC);
+ } else {
+ systemServicePowerMah = calculatePowerUsingPowerProfile(batteryStats);
+ }
+
final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
builder.getUidBatteryConsumerBuilders();
final UidBatteryConsumer.Builder systemServerConsumer = uidBatteryConsumerBuilders.get(
@@ -76,7 +93,7 @@
// distributed to applications
systemServerConsumer.setConsumedPower(
BatteryConsumer.POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS,
- -systemServicePowerMah);
+ -systemServicePowerMah, powerModel);
}
for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
@@ -84,7 +101,8 @@
if (app != systemServerConsumer) {
final BatteryStats.Uid uid = app.getBatteryStatsUid();
app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES,
- systemServicePowerMah * uid.getProportionalSystemServiceUsage());
+ systemServicePowerMah * uid.getProportionalSystemServiceUsage(),
+ powerModel);
}
}
@@ -102,7 +120,20 @@
public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
long rawRealtimeUs, long rawUptimeUs, int statsType,
SparseArray<UserHandle> asUsers) {
- double systemServicePowerMah = calculateSystemServicePower(batteryStats);
+ final BatteryStats.Uid systemUid = batteryStats.getUidStats().get(Process.SYSTEM_UID);
+ if (systemUid == null) {
+ return;
+ }
+
+ final long consumptionUC = systemUid.getCpuMeasuredBatteryConsumptionUC();
+ double systemServicePowerMah;
+ if (getPowerModel(consumptionUC) == BatteryConsumer.POWER_MODEL_MEASURED_ENERGY) {
+ systemServicePowerMah = calculatePowerUsingMeasuredConsumption(batteryStats,
+ systemUid, consumptionUC);
+ } else {
+ systemServicePowerMah = calculatePowerUsingPowerProfile(batteryStats);
+ }
+
BatterySipper systemServerSipper = null;
for (int i = sippers.size() - 1; i >= 0; i--) {
final BatterySipper app = sippers.get(i);
@@ -134,7 +165,21 @@
}
}
- private double calculateSystemServicePower(BatteryStats batteryStats) {
+ private double calculatePowerUsingMeasuredConsumption(BatteryStats batteryStats,
+ BatteryStats.Uid systemUid, long consumptionUC) {
+ // Use the PowerProfile based model to estimate the ratio between the power consumed
+ // while handling incoming binder calls and the entire System UID power consumption.
+ // Apply that ratio to the _measured_ system UID power consumption to get a more
+ // accurate estimate of the power consumed by incoming binder calls.
+ final double systemServiceModeledPowerMah = calculatePowerUsingPowerProfile(batteryStats);
+ final double systemUidModeledPowerMah = mCpuPowerCalculator.calculateUidModeledPowerMah(
+ systemUid, BatteryStats.STATS_SINCE_CHARGED);
+
+ return uCtoMah(consumptionUC) * systemServiceModeledPowerMah
+ / systemUidModeledPowerMah;
+ }
+
+ private double calculatePowerUsingPowerProfile(BatteryStats batteryStats) {
final long[] systemServiceTimeAtCpuSpeeds = batteryStats.getSystemServiceTimeAtCpuSpeeds();
if (systemServiceTimeAtCpuSpeeds == null) {
return 0;
@@ -145,13 +190,12 @@
double powerMah = 0;
final int size = Math.min(mPowerEstimators.length, systemServiceTimeAtCpuSpeeds.length);
for (int i = 0; i < size; i++) {
- powerMah += mPowerEstimators[i].calculatePower(systemServiceTimeAtCpuSpeeds[i]);
+ powerMah += mPowerEstimators[i].calculatePower(systemServiceTimeAtCpuSpeeds[i] / 1000);
}
if (DEBUG) {
Log.d(TAG, "System service power:" + powerMah);
}
-
return powerMah;
}
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 084d4d1..f457c56 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2890,7 +2890,13 @@
<permission android:name="android.permission.SET_DISPLAY_OFFSET"
android:protectionLevel="signature|privileged" />
- <!-- Allows a companion app to run in the background.
+ <!-- Allows a companion app to run in the background. This permission implies
+ {@link android.Manifest.permission#REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND},
+ and allows to start a foreground service from the background.
+ If an app does not have to run in the background, but only needs to start a foreground
+ service from the background, consider using
+ {@link android.Manifest.permission#REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND},
+ which is less powerful.
<p>Protection level: normal
-->
<permission android:name="android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND"
@@ -2900,6 +2906,7 @@
<!-- Allows a companion app to start a foreground service from the background.
{@see android.Manifest.permission#REQUEST_COMPANION_RUN_IN_BACKGROUND}
+ <p>Protection level: normal
-->
<permission android:name="android.permission.REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND"
android:protectionLevel="normal"/>
diff --git a/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java b/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java
index bee0a0b..333eebb 100644
--- a/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java
+++ b/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java
@@ -48,9 +48,8 @@
@Test
public void testGetStatsProto() {
- final long sessionEndTimestampMs = 1050;
final BatteryUsageStats bus = buildBatteryUsageStats();
- final byte[] bytes = bus.getStatsProto(sessionEndTimestampMs);
+ final byte[] bytes = bus.getStatsProto();
BatteryUsageStatsAtomsProto proto;
try {
proto = BatteryUsageStatsAtomsProto.parseFrom(bytes);
@@ -60,9 +59,9 @@
}
assertEquals(bus.getStatsStartTimestamp(), proto.sessionStartMillis);
- assertEquals(sessionEndTimestampMs, proto.sessionEndMillis);
+ assertEquals(bus.getStatsEndTimestamp(), proto.sessionEndMillis);
assertEquals(
- sessionEndTimestampMs - bus.getStatsStartTimestamp(),
+ bus.getStatsEndTimestamp() - bus.getStatsStartTimestamp(),
proto.sessionDurationMillis);
assertEquals(bus.getDischargePercentage(), proto.sessionDischargePercentage);
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
index cd45060..a36d9fe 100644
--- a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
@@ -18,25 +18,28 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.os.BatteryConsumer;
-import android.os.BatteryStats;
-import android.os.BatteryUsageStatsQuery;
import android.os.Binder;
import android.os.Process;
-import android.os.UidBatteryConsumer;
-import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.power.MeasuredEnergyStats;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.io.IOException;
import java.util.ArrayList;
@@ -47,6 +50,8 @@
public class SystemServicePowerCalculatorTest {
private static final double PRECISION = 0.000001;
+ private static final int APP_UID1 = 100;
+ private static final int APP_UID2 = 200;
@Rule
public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
@@ -61,73 +66,52 @@
.setAveragePowerForCpuCore(1, 0, 500)
.setAveragePowerForCpuCore(1, 1, 600);
+ @Mock
private BatteryStatsImpl.UserInfoProvider mMockUserInfoProvider;
+ @Mock
+ private KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader mMockKernelCpuUidClusterTimeReader;
+ @Mock
+ private KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader mMockCpuUidFreqTimeReader;
+ @Mock
+ private KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader mMockKernelCpuUidUserSysTimeReader;
+ @Mock
+ private KernelCpuUidTimeReader.KernelCpuUidActiveTimeReader mMockKerneCpuUidActiveTimeReader;
+ @Mock
+ private SystemServerCpuThreadReader mMockSystemServerCpuThreadReader;
+
+ private final KernelCpuSpeedReader[] mMockKernelCpuSpeedReaders = new KernelCpuSpeedReader[]{
+ mock(KernelCpuSpeedReader.class),
+ mock(KernelCpuSpeedReader.class),
+ };
+
private MockBatteryStatsImpl mMockBatteryStats;
- private MockKernelCpuUidFreqTimeReader mMockCpuUidFreqTimeReader;
- private MockSystemServerCpuThreadReader mMockSystemServerCpuThreadReader;
@Before
public void setUp() throws IOException {
- mMockUserInfoProvider = mock(BatteryStatsImpl.UserInfoProvider.class);
- mMockSystemServerCpuThreadReader = new MockSystemServerCpuThreadReader();
- mMockCpuUidFreqTimeReader = new MockKernelCpuUidFreqTimeReader();
+ MockitoAnnotations.initMocks(this);
mMockBatteryStats = mStatsRule.getBatteryStats()
- .setSystemServerCpuThreadReader(mMockSystemServerCpuThreadReader)
+ .setUserInfoProvider(mMockUserInfoProvider)
+ .setKernelCpuSpeedReaders(mMockKernelCpuSpeedReaders)
.setKernelCpuUidFreqTimeReader(mMockCpuUidFreqTimeReader)
- .setUserInfoProvider(mMockUserInfoProvider);
+ .setKernelCpuUidClusterTimeReader(mMockKernelCpuUidClusterTimeReader)
+ .setKernelCpuUidUserSysTimeReader(mMockKernelCpuUidUserSysTimeReader)
+ .setKernelCpuUidActiveTimeReader(mMockKerneCpuUidActiveTimeReader)
+ .setSystemServerCpuThreadReader(mMockSystemServerCpuThreadReader);
}
@Test
public void testPowerProfileBasedModel() {
- when(mMockUserInfoProvider.exists(anyInt())).thenReturn(true);
-
- // Test Power Profile has two CPU clusters with 2 speeds each, thus 4 freq times total
- mMockSystemServerCpuThreadReader.setCpuTimes(
- new long[] {30000, 40000, 50000, 60000},
- new long[] {20000, 30000, 40000, 50000});
-
- mMockCpuUidFreqTimeReader.setSystemServerCpuTimes(
- new long[] {10000, 20000, 30000, 40000}
- );
-
- mMockBatteryStats.readKernelUidCpuFreqTimesLocked(null, true, false, null);
-
- int workSourceUid1 = 100;
- int workSourceUid2 = 200;
- int transactionCode = 42;
-
- Collection<BinderCallsStats.CallStat> callStats = new ArrayList<>();
- BinderCallsStats.CallStat stat1 = new BinderCallsStats.CallStat(workSourceUid1,
- Binder.class, transactionCode, true /*screenInteractive */);
- stat1.incrementalCallCount = 100;
- stat1.recordedCallCount = 100;
- stat1.cpuTimeMicros = 1000000;
- callStats.add(stat1);
-
- mMockBatteryStats.noteBinderCallStats(workSourceUid1, 100, callStats);
-
- callStats.clear();
- BinderCallsStats.CallStat stat2 = new BinderCallsStats.CallStat(workSourceUid2,
- Binder.class, transactionCode, true /*screenInteractive */);
- stat2.incrementalCallCount = 100;
- stat2.recordedCallCount = 100;
- stat2.cpuTimeMicros = 9000000;
- callStats.add(stat2);
-
- mMockBatteryStats.noteBinderCallStats(workSourceUid2, 100, callStats);
-
- mMockBatteryStats.updateSystemServiceCallStats();
- mMockBatteryStats.updateSystemServerThreadStats();
+ prepareBatteryStats(null);
SystemServicePowerCalculator calculator = new SystemServicePowerCalculator(
mStatsRule.getPowerProfile());
- mStatsRule.apply(new FakeCpuPowerCalculator(), calculator);
+ mStatsRule.apply(new CpuPowerCalculator(mStatsRule.getPowerProfile()), calculator);
- assertThat(mStatsRule.getUidBatteryConsumer(workSourceUid1)
+ assertThat(mStatsRule.getUidBatteryConsumer(APP_UID1)
.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES))
.isWithin(PRECISION).of(1.888888);
- assertThat(mStatsRule.getUidBatteryConsumer(workSourceUid2)
+ assertThat(mStatsRule.getUidBatteryConsumer(APP_UID2)
.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES))
.isWithin(PRECISION).of(17.0);
assertThat(mStatsRule.getUidBatteryConsumer(Process.SYSTEM_UID)
@@ -141,58 +125,105 @@
.isWithin(PRECISION).of(18.888888);
}
- private static class MockKernelCpuUidFreqTimeReader extends
- KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader {
- private long[] mSystemServerCpuTimes;
+ @Test
+ public void testMeasuredEnergyBasedModel() {
+ final boolean[] supportedPowerBuckets =
+ new boolean[MeasuredEnergyStats.NUMBER_STANDARD_POWER_BUCKETS];
+ supportedPowerBuckets[MeasuredEnergyStats.POWER_BUCKET_CPU] = true;
+ mStatsRule.getBatteryStats()
+ .initMeasuredEnergyStatsLocked(supportedPowerBuckets, new String[0]);
- MockKernelCpuUidFreqTimeReader() {
- super(/*throttle */false);
- }
+ prepareBatteryStats(new long[]{50000000, 100000000});
- void setSystemServerCpuTimes(long[] systemServerCpuTimes) {
- mSystemServerCpuTimes = systemServerCpuTimes;
- }
+ SystemServicePowerCalculator calculator = new SystemServicePowerCalculator(
+ mStatsRule.getPowerProfile());
- @Override
- public boolean perClusterTimesAvailable() {
- return true;
- }
+ mStatsRule.apply(new CpuPowerCalculator(mStatsRule.getPowerProfile()), calculator);
- @Override
- public void readDelta(boolean forcedRead, @Nullable Callback<long[]> cb) {
- if (cb != null) {
- cb.onUidCpuTime(Process.SYSTEM_UID, mSystemServerCpuTimes);
- }
- }
+ assertThat(mStatsRule.getUidBatteryConsumer(APP_UID1)
+ .getConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES))
+ .isWithin(PRECISION).of(1.979351);
+ assertThat(mStatsRule.getUidBatteryConsumer(APP_UID2)
+ .getConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES))
+ .isWithin(PRECISION).of(17.814165);
+ assertThat(mStatsRule.getUidBatteryConsumer(Process.SYSTEM_UID)
+ .getConsumedPower(BatteryConsumer.POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS))
+ .isWithin(PRECISION).of(-19.793517);
+ assertThat(mStatsRule.getDeviceBatteryConsumer()
+ .getConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES))
+ .isWithin(PRECISION).of(19.793517);
+ assertThat(mStatsRule.getAppsBatteryConsumer()
+ .getConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES))
+ .isWithin(PRECISION).of(19.793517);
}
- private static class MockSystemServerCpuThreadReader extends SystemServerCpuThreadReader {
- private final SystemServiceCpuThreadTimes mThreadTimes = new SystemServiceCpuThreadTimes();
+ private void prepareBatteryStats(long[] clusterChargesUc) {
+ when(mMockUserInfoProvider.exists(anyInt())).thenReturn(true);
- MockSystemServerCpuThreadReader() {
- super(null);
- }
+ when(mMockKernelCpuSpeedReaders[0].readDelta()).thenReturn(new long[]{1000, 2000});
+ when(mMockKernelCpuSpeedReaders[1].readDelta()).thenReturn(new long[]{3000, 4000});
- public void setCpuTimes(long[] threadCpuTimesUs, long[] binderThreadCpuTimesUs) {
- mThreadTimes.threadCpuTimesUs = threadCpuTimesUs;
- mThreadTimes.binderThreadCpuTimesUs = binderThreadCpuTimesUs;
- }
+ when(mMockCpuUidFreqTimeReader.perClusterTimesAvailable()).thenReturn(false);
- @Override
- public SystemServiceCpuThreadTimes readDelta() {
- return mThreadTimes;
- }
- }
+ // User/System CPU time in microseconds
+ doAnswer(invocation -> {
+ final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(1);
+ callback.onUidCpuTime(APP_UID1, new long[]{1_000_000, 2_000_000});
+ callback.onUidCpuTime(APP_UID2, new long[]{3_000_000, 4_000_000});
+ callback.onUidCpuTime(Process.SYSTEM_UID, new long[]{60_000_000, 80_000_000});
+ return null;
+ }).when(mMockKernelCpuUidUserSysTimeReader).readDelta(anyBoolean(), any());
- private static class FakeCpuPowerCalculator extends PowerCalculator {
- @Override
- protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
- long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
- if (u.getUid() == Process.SYSTEM_UID) {
- // SystemServer must be attributed at least as much power as the total
- // of all system services requested by apps.
- app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, 1000000);
- }
- }
+ // Active CPU time in milliseconds
+ doAnswer(invocation -> {
+ final KernelCpuUidTimeReader.Callback<Long> callback = invocation.getArgument(1);
+ callback.onUidCpuTime(APP_UID1, 1111L);
+ callback.onUidCpuTime(APP_UID2, 3333L);
+ callback.onUidCpuTime(Process.SYSTEM_UID, 10000L);
+ return null;
+ }).when(mMockKerneCpuUidActiveTimeReader).readDelta(anyBoolean(), any());
+
+ // Per-cluster CPU time in milliseconds
+ doAnswer(invocation -> {
+ final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(1);
+ callback.onUidCpuTime(APP_UID1, new long[]{1111, 2222});
+ callback.onUidCpuTime(APP_UID2, new long[]{3333, 4444});
+ callback.onUidCpuTime(Process.SYSTEM_UID, new long[]{50_000, 80_000});
+ return null;
+ }).when(mMockKernelCpuUidClusterTimeReader).readDelta(anyBoolean(), any());
+
+ // System service CPU time
+ final SystemServerCpuThreadReader.SystemServiceCpuThreadTimes threadTimes =
+ new SystemServerCpuThreadReader.SystemServiceCpuThreadTimes();
+ threadTimes.binderThreadCpuTimesUs =
+ new long[]{20_000_000, 30_000_000, 40_000_000, 50_000_000};
+
+ when(mMockSystemServerCpuThreadReader.readDelta()).thenReturn(threadTimes);
+
+ int transactionCode = 42;
+
+ Collection<BinderCallsStats.CallStat> callStats = new ArrayList<>();
+ BinderCallsStats.CallStat stat1 = new BinderCallsStats.CallStat(APP_UID1,
+ Binder.class, transactionCode, true /*screenInteractive */);
+ stat1.incrementalCallCount = 100;
+ stat1.recordedCallCount = 100;
+ stat1.cpuTimeMicros = 1_000_000;
+ callStats.add(stat1);
+
+ mMockBatteryStats.noteBinderCallStats(APP_UID1, 100, callStats);
+
+ callStats.clear();
+ BinderCallsStats.CallStat stat2 = new BinderCallsStats.CallStat(APP_UID2,
+ Binder.class, transactionCode, true /*screenInteractive */);
+ stat2.incrementalCallCount = 100;
+ stat2.recordedCallCount = 100;
+ stat2.cpuTimeMicros = 9_000_000;
+ callStats.add(stat2);
+
+ mMockBatteryStats.noteBinderCallStats(APP_UID2, 100, callStats);
+
+ mMockBatteryStats.updateCpuTimeLocked(true, true, clusterChargesUc);
+
+ mMockBatteryStats.prepareForDumpLocked();
}
}
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index be45f18..7ad46a1 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -975,7 +975,7 @@
shader.setColor(color, effectColor);
shader.setOrigin(cx, cy);
shader.setTouch(x, y);
- shader.setResolution(w, h, mState.mDensity);
+ shader.setResolution(w, h);
shader.setNoisePhase(noisePhase);
shader.setRadius(radius);
shader.setProgress(.0f);
@@ -1193,6 +1193,9 @@
mRipplePaint = new Paint();
mRipplePaint.setAntiAlias(true);
mRipplePaint.setStyle(Paint.Style.FILL);
+ if (mState.mRippleStyle == STYLE_PATTERNED) {
+ mRipplePaint.setDither(true);
+ }
}
final float x = mHotspotBounds.exactCenterX();
diff --git a/graphics/java/android/graphics/drawable/RippleShader.java b/graphics/java/android/graphics/drawable/RippleShader.java
index eb726c1..57b3223 100644
--- a/graphics/java/android/graphics/drawable/RippleShader.java
+++ b/graphics/java/android/graphics/drawable/RippleShader.java
@@ -20,7 +20,6 @@
import android.graphics.Color;
import android.graphics.RuntimeShader;
import android.graphics.Shader;
-import android.util.DisplayMetrics;
final class RippleShader extends RuntimeShader {
private static final String SHADER_UNIFORMS = "uniform vec2 in_origin;\n"
@@ -204,8 +203,8 @@
sparkleColor.green(), sparkleColor.blue(), sparkleColor.alpha()});
}
- public void setResolution(float w, float h, int density) {
- final float densityScale = density * DisplayMetrics.DENSITY_DEFAULT_SCALE * 0.8f;
+ public void setResolution(float w, float h) {
+ final float densityScale = 2.1f;
setUniform("in_resolutionScale", new float[] {1f / w, 1f / h});
setUniform("in_noiseScale", new float[] {densityScale / w, densityScale / h});
}
diff --git a/location/java/android/location/LocationDeviceConfig.java b/location/java/android/location/LocationDeviceConfig.java
index 9284574..c55eed9 100644
--- a/location/java/android/location/LocationDeviceConfig.java
+++ b/location/java/android/location/LocationDeviceConfig.java
@@ -16,16 +16,11 @@
package android.location;
-import android.annotation.SystemApi;
-import android.annotation.TestApi;
-
/**
* DeviceConfig keys within the location namespace.
*
* @hide
*/
-@SystemApi
-@TestApi
public final class LocationDeviceConfig {
/**
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index f83dc40..ae44c5e 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1823,6 +1823,7 @@
* @deprecated Use {@link #isProviderPackage(String, String, String)} instead.
*
* @hide
+ * @removed
*/
@Deprecated
@SystemApi
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/SettingsTransitionActivity.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/SettingsTransitionActivity.java
index 4c45c5e..8c2621d 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/SettingsTransitionActivity.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/SettingsTransitionActivity.java
@@ -16,6 +16,8 @@
package com.android.settingslib.collapsingtoolbar;
+import static com.android.settingslib.transition.SettingsTransitionHelper.EXTRA_PAGE_TRANSITION_TYPE;
+
import android.app.ActivityOptions;
import android.content.Intent;
import android.os.Bundle;
@@ -28,6 +30,7 @@
import androidx.fragment.app.FragmentActivity;
import com.android.settingslib.transition.SettingsTransitionHelper;
+import com.android.settingslib.transition.SettingsTransitionHelper.TransitionType;
/**
* A base Activity for Settings-specific page transition. Activities extending it will get
@@ -35,7 +38,6 @@
*/
public abstract class SettingsTransitionActivity extends FragmentActivity {
private static final String TAG = "SettingsTransitionActivity";
- private static final int DEFAULT_REQUEST = -1;
private Toolbar mToolbar;
@@ -58,45 +60,17 @@
}
@Override
- public void startActivity(Intent intent) {
- if (!isSettingsTransitionEnabled()) {
- super.startActivity(intent);
- return;
- }
-
- super.startActivity(intent, createActivityOptionsBundleForTransition(null));
- }
-
- @Override
- public void startActivity(Intent intent, @Nullable Bundle options) {
- if (!isSettingsTransitionEnabled()) {
- super.startActivity(intent, options);
- return;
- }
-
- super.startActivity(intent, createActivityOptionsBundleForTransition(options));
- }
-
- @Override
- public void startActivityForResult(Intent intent, int requestCode) {
- if (!isSettingsTransitionEnabled() || requestCode == DEFAULT_REQUEST) {
- super.startActivityForResult(intent, requestCode);
- return;
- }
-
- super.startActivityForResult(intent, requestCode, createActivityOptionsBundleForTransition(
- null));
- }
-
- @Override
public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
- if (!isSettingsTransitionEnabled() || requestCode == DEFAULT_REQUEST) {
+ final int transitionType = intent.getIntExtra(EXTRA_PAGE_TRANSITION_TYPE,
+ TransitionType.TRANSITION_SHARED_AXIS);
+ if (!isSettingsTransitionEnabled() ||
+ transitionType == TransitionType.TRANSITION_NONE) {
super.startActivityForResult(intent, requestCode, options);
return;
}
- super.startActivityForResult(intent, requestCode, createActivityOptionsBundleForTransition(
- options));
+ super.startActivityForResult(intent, requestCode,
+ createActivityOptionsBundleForTransition(options));
}
protected boolean isSettingsTransitionEnabled() {
diff --git a/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java b/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java
index 3d93964..4612861 100644
--- a/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java
+++ b/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java
@@ -55,6 +55,8 @@
int TRANSITION_FADE = 2;
}
+ public static final String EXTRA_PAGE_TRANSITION_TYPE = "page_transition_type";
+
private static final String TAG = "SettingsTransitionHelper";
private static final long DURATION = 450L;
private static final float FADE_THROUGH_THRESHOLD = 0.22F;
diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
index b3c4374..989010e 100644
--- a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
+++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
@@ -114,6 +114,11 @@
* Set or clear next alarm information
*/
void setNextAlarm(@Nullable Drawable image, @Nullable String description);
+
+ /**
+ * Set or clear device media playing
+ */
+ void setMediaTarget(@Nullable SmartspaceTarget target);
}
/** Interface for launching Intents, which can differ on the lockscreen */
diff --git a/packages/SystemUI/res/layout-land/volume_dialog.xml b/packages/SystemUI/res/layout-land/volume_dialog.xml
index b08e513..f1cda27 100644
--- a/packages/SystemUI/res/layout-land/volume_dialog.xml
+++ b/packages/SystemUI/res/layout-land/volume_dialog.xml
@@ -126,6 +126,7 @@
android:gravity="right"
android:layout_gravity="right"
android:clipToPadding="false"
+ android:clipToOutline="true"
android:background="@drawable/volume_row_rounded_background">
<com.android.systemui.volume.CaptionsToggleImageButton
android:id="@+id/odi_captions_icon"
@@ -146,6 +147,7 @@
android:layout="@layout/volume_tool_tip_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="bottom | right"/>
+ android:layout_gravity="bottom | right"
+ android:layout_marginRight="@dimen/volume_tool_tip_right_margin"/>
</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_carousel.xml b/packages/SystemUI/res/layout/media_carousel.xml
index 87acfd0..52132e8 100644
--- a/packages/SystemUI/res/layout/media_carousel.xml
+++ b/packages/SystemUI/res/layout/media_carousel.xml
@@ -22,6 +22,7 @@
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
+ android:forceHasOverlappingRendering="false"
android:theme="@style/MediaPlayer">
<com.android.systemui.media.MediaScrollView
android:id="@+id/media_carousel_scroller"
diff --git a/packages/SystemUI/res/layout/people_tile_large_with_content.xml b/packages/SystemUI/res/layout/people_tile_large_with_content.xml
index e294dad..b7e86a3 100644
--- a/packages/SystemUI/res/layout/people_tile_large_with_content.xml
+++ b/packages/SystemUI/res/layout/people_tile_large_with_content.xml
@@ -14,6 +14,7 @@
~ limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
@@ -52,7 +53,7 @@
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
- android:textColor="?android:attr/textColorPrimary"
+ android:textColor="?androidprv:attr/textColorOnAccent"
android:background="@drawable/people_space_messages_count_background"
android:textSize="14sp"
android:maxLines="1"
diff --git a/packages/SystemUI/res/layout/people_tile_medium_with_content.xml b/packages/SystemUI/res/layout/people_tile_medium_with_content.xml
index 47cab42..1086a13 100644
--- a/packages/SystemUI/res/layout/people_tile_medium_with_content.xml
+++ b/packages/SystemUI/res/layout/people_tile_medium_with_content.xml
@@ -16,6 +16,7 @@
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:id="@+id/item"
android:background="@drawable/people_space_tile_view_card"
@@ -128,7 +129,7 @@
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
- android:textColor="?android:attr/textColorPrimary"
+ android:textColor="?androidprv:attr/textColorOnAccent"
android:background="@drawable/people_space_messages_count_background"
android:textSize="14sp"
android:maxLines="1"
diff --git a/packages/SystemUI/res/layout/people_tile_small.xml b/packages/SystemUI/res/layout/people_tile_small.xml
index 7a1371d..22fcd3b 100644
--- a/packages/SystemUI/res/layout/people_tile_small.xml
+++ b/packages/SystemUI/res/layout/people_tile_small.xml
@@ -14,6 +14,7 @@
~ limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -50,7 +51,7 @@
android:gravity="center"
android:paddingHorizontal="8dp"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
- android:textColor="?android:attr/textColorPrimary"
+ android:textColor="?androidprv:attr/textColorOnAccent"
android:background="@drawable/people_space_messages_count_background"
android:textSize="@dimen/name_text_size_for_small"
android:maxLines="1"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index c16f13e..fb39d3e 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -129,7 +129,22 @@
android:layout_marginTop="@dimen/status_bar_header_height_keyguard"
android:text="@string/report_rejected_touch"
android:visibility="gone" />
-
+ <com.android.systemui.statusbar.phone.TapAgainView
+ android:id="@+id/shade_falsing_tap_again"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ systemui:layout_constraintLeft_toLeftOf="parent"
+ systemui:layout_constraintRight_toRightOf="parent"
+ systemui:layout_constraintBottom_toBottomOf="parent"
+ android:layout_marginBottom="20dp"
+ android:paddingHorizontal="16dp"
+ android:minHeight="44dp"
+ android:elevation="4dp"
+ android:background="@drawable/rounded_bg_full"
+ android:gravity="center"
+ android:text="@string/tap_again"
+ android:visibility="gone"
+ />
</com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer>
<FrameLayout
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index beac057..51718d9 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -125,6 +125,7 @@
android:gravity="right"
android:layout_gravity="right"
android:clipToPadding="false"
+ android:clipToOutline="true"
android:background="@drawable/volume_row_rounded_background">
<com.android.systemui.volume.CaptionsToggleImageButton
android:id="@+id/odi_captions_icon"
@@ -146,7 +147,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom | right"
- android:layout_marginRight="@dimen/volume_tool_tip_right_margin"
- android:layout_marginBottom="@dimen/volume_tool_tip_bottom_margin"/>
+ android:layout_marginRight="@dimen/volume_tool_tip_right_margin"/>
</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index 1b0076c..ee89b97 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -60,6 +60,7 @@
android:thumb="@null"
android:splitTrack="false"
android:progressDrawable="@drawable/volume_row_seekbar"
+ android:background="@null"
android:layoutDirection="ltr"
android:rotation="270" />
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/volume_tool_tip_view.xml b/packages/SystemUI/res/layout/volume_tool_tip_view.xml
index 9fe885e..ee24969 100644
--- a/packages/SystemUI/res/layout/volume_tool_tip_view.xml
+++ b/packages/SystemUI/res/layout/volume_tool_tip_view.xml
@@ -17,6 +17,7 @@
<com.android.systemui.volume.VolumeToolTipView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:id="@+id/tooltip_view"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
@@ -35,7 +36,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- android:textColor="@android:color/white"
+ android:textColor="?android:attr/textColorPrimaryInverse"
android:text="@string/volume_odi_captions_tip"
android:textSize="14sp"/>
<ImageView
@@ -48,7 +49,7 @@
android:layout_marginEnd="2dp"
android:alpha="0.7"
android:src="@drawable/ic_remove_no_shadow"
- android:tint="@android:color/white"
+ android:tint="?android:attr/textColorPrimaryInverse"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/accessibility_volume_close_odi_captions_tip"/>
</LinearLayout>
diff --git a/packages/SystemUI/res/values-land-television/dimens.xml b/packages/SystemUI/res/values-land-television/dimens.xml
index 220ed5c..a9bc9e5 100644
--- a/packages/SystemUI/res/values-land-television/dimens.xml
+++ b/packages/SystemUI/res/values-land-television/dimens.xml
@@ -23,6 +23,7 @@
<dimen name="volume_dialog_slider_width">4dp</dimen>
<dimen name="volume_dialog_slider_corner_radius">@dimen/volume_dialog_slider_width</dimen>
<dimen name="volume_dialog_background_blur_radius">100dp</dimen>
+ <dimen name="volume_tool_tip_right_margin">136dp</dimen>
<dimen name="tv_volume_dialog_bubble_size">36dp</dimen>
<dimen name="tv_volume_dialog_row_padding">6dp</dimen>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 215698d..9df9db6 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -43,7 +43,6 @@
<dimen name="qs_detail_margin_top">14dp</dimen>
- <dimen name="volume_tool_tip_right_margin">136dp</dimen>
<dimen name="volume_tool_tip_top_margin">12dp</dimen>
<dimen name="volume_row_slider_height">128dp</dimen>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index b2ab5f7..5c1e935 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1418,10 +1418,6 @@
<dimen name="media_output_dialog_icon_corner_radius">16dp</dimen>
<dimen name="media_output_dialog_title_anim_y_delta">12.5dp</dimen>
- <!-- Delay after which the media will start transitioning to the full shade on
- the lockscreen -->
- <dimen name="lockscreen_shade_media_transition_start_delay">40dp</dimen>
-
<!-- Distance that the full shade transition takes in order for qs to fully transition to the
shade -->
<dimen name="lockscreen_shade_qs_transition_distance">200dp</dimen>
@@ -1430,13 +1426,16 @@
the shade (in alpha) -->
<dimen name="lockscreen_shade_scrim_transition_distance">80dp</dimen>
- <!-- Extra inset for the notifications when accounting for media during the lockscreen to
- shade transition to compensate for the disappearing media -->
- <dimen name="lockscreen_shade_transition_extra_media_inset">-48dp</dimen>
+ <!-- Distance that the full shade transition takes in order for media to fully transition to
+ the shade -->
+ <dimen name="lockscreen_shade_media_transition_distance">140dp</dimen>
<!-- Maximum overshoot for the topPadding of notifications when transitioning to the full
shade -->
- <dimen name="lockscreen_shade_max_top_overshoot">32dp</dimen>
+ <dimen name="lockscreen_shade_notification_movement">24dp</dimen>
+
+ <!-- Maximum overshoot for the pulse expansion -->
+ <dimen name="pulse_expansion_max_top_overshoot">16dp</dimen>
<dimen name="people_space_widget_radius">28dp</dimen>
<dimen name="people_space_image_radius">20dp</dimen>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index 6393147..f4086ed 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -38,8 +38,6 @@
<!-- The new animations to/from lockscreen and AOD! -->
<bool name="flag_lockscreen_animations">false</bool>
- <bool name="flag_toast_style">false</bool>
-
<bool name="flag_pm_lite">false</bool>
<bool name="flag_alarm_tile">false</bool>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 01d0dde..db3fae6 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1062,6 +1062,9 @@
<!-- Shows to explain the double tap interaction with notifications: After tapping a notification on Keyguard, this will explain users to tap again to launch a notification. [CHAR LIMIT=60] -->
<string name="notification_tap_again">Tap again to open</string>
+ <!-- Asks for a second tap as confirmation on an item that normally requires one tap. [CHAR LIMIT=60] -->
+ <string name="tap_again">Tap again</string>
+
<!-- Message shown when lock screen is tapped or face authentication fails. [CHAR LIMIT=60] -->
<string name="keyguard_unlock">Swipe up to open</string>
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index f98a959..b2ae2a0 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -40,7 +40,8 @@
name: "SystemUISharedLib",
srcs: [
"src/**/*.java",
- "src/**/I*.aidl",
+ "src/**/*.kt",
+ "src/**/*.aidl",
":wm_shell-aidls",
],
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 2cf3ad2..c468e41 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -36,6 +36,9 @@
* Various shared constants between Launcher and SysUI as part of quickstep
*/
public class QuickStepContract {
+ // Fully qualified name of the Launcher activity.
+ public static final String LAUNCHER_ACTIVITY_CLASS_NAME =
+ "com.google.android.apps.nexuslauncher.NexusLauncherActivity";
public static final String KEY_EXTRA_SYSUI_PROXY = "extra_sysui_proxy";
public static final String KEY_EXTRA_WINDOW_CORNER_RADIUS = "extra_window_corner_radius";
@@ -52,6 +55,8 @@
// See IStartingWindow.aidl
public static final String KEY_EXTRA_SHELL_STARTING_WINDOW =
"extra_shell_starting_window";
+ // See ISmartspaceTransitionController.aidl
+ public static final String KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER = "smartspace_transition";
public static final String NAV_BAR_MODE_2BUTTON_OVERLAY =
WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceCallback.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceCallback.aidl
new file mode 100644
index 0000000..511df4c
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceCallback.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.system.smartspace;
+
+import com.android.systemui.shared.system.smartspace.SmartspaceState;
+
+// Methods for getting and setting the state of a SmartSpace. This is used to allow a remote process
+// (such as System UI) to sync with and control a SmartSpace view hosted in another process (such as
+// Launcher).
+interface ISmartspaceCallback {
+
+ // Return information about the state of the SmartSpace, including location on-screen and
+ // currently selected page.
+ SmartspaceState getSmartspaceState();
+
+ // Set the currently selected page of this SmartSpace.
+ oneway void setSelectedPage(int selectedPage);
+
+ oneway void setVisibility(int visibility);
+}
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceTransitionController.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceTransitionController.aidl
new file mode 100644
index 0000000..2b3e961
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceTransitionController.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.system.smartspace;
+
+import com.android.systemui.shared.system.smartspace.ISmartspaceCallback;
+
+// Controller that keeps track of SmartSpace instances in remote processes (such as Launcher).
+interface ISmartspaceTransitionController {
+ oneway void setSmartspace(ISmartspaceCallback callback);
+}
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.aidl
new file mode 100644
index 0000000..2d01d6a
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.system.smartspace;
+
+import com.android.systemui.shared.system.smartspace.SmartspaceState;
+
+parcelable SmartspaceState;
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt
new file mode 100644
index 0000000..2d51c4d
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.system.smartspace
+
+import android.graphics.Rect
+import android.os.Parcel
+import android.os.Parcelable
+
+/**
+ * Represents the state of a SmartSpace, including its location on screen and the index of the
+ * currently selected page. This object contains all of the information needed to synchronize two
+ * SmartSpace instances so that we can perform shared-element transitions between them.
+ */
+class SmartspaceState() : Parcelable {
+ var boundsOnScreen: Rect = Rect()
+ var selectedPage = 0
+
+ constructor(parcel: Parcel) : this() {
+ this.boundsOnScreen = parcel.readParcelable(Rect::javaClass.javaClass.classLoader)
+ this.selectedPage = parcel.readInt()
+ }
+
+ override fun writeToParcel(dest: Parcel?, flags: Int) {
+ dest?.writeParcelable(boundsOnScreen, 0)
+ dest?.writeInt(selectedPage)
+ }
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ override fun toString(): String {
+ return "boundsOnScreen: $boundsOnScreen, selectedPage: $selectedPage"
+ }
+
+ companion object CREATOR : Parcelable.Creator<SmartspaceState> {
+ override fun createFromParcel(parcel: Parcel): SmartspaceState {
+ return SmartspaceState(parcel)
+ }
+
+ override fun newArray(size: Int): Array<SmartspaceState?> {
+ return arrayOfNulls(size)
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index aa7f9a2..28534d3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -32,8 +32,10 @@
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
@@ -44,7 +46,9 @@
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.util.ViewController;
+import java.util.HashSet;
import java.util.Locale;
+import java.util.Set;
import java.util.TimeZone;
import javax.inject.Inject;
@@ -92,6 +96,9 @@
// If set, will replace keyguard_status_area
private View mSmartspaceView;
+ private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ private SmartspaceTransitionController mSmartspaceTransitionController;
+
@Inject
public KeyguardClockSwitchController(
KeyguardClockSwitch keyguardClockSwitch,
@@ -104,7 +111,9 @@
BatteryController batteryController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
KeyguardBypassController bypassController,
- LockscreenSmartspaceController smartspaceController) {
+ LockscreenSmartspaceController smartspaceController,
+ KeyguardUnlockAnimationController keyguardUnlockAnimationController,
+ SmartspaceTransitionController smartspaceTransitionController) {
super(keyguardClockSwitch);
mStatusBarStateController = statusBarStateController;
mColorExtractor = colorExtractor;
@@ -116,6 +125,9 @@
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mBypassController = bypassController;
mSmartspaceController = smartspaceController;
+
+ mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
+ mSmartspaceTransitionController = smartspaceTransitionController;
}
/**
@@ -187,6 +199,7 @@
nic.setLayoutParams(lp);
mView.setSmartspaceView(mSmartspaceView);
+ mSmartspaceTransitionController.setLockscreenSmartspace(mSmartspaceView);
}
}
@@ -285,12 +298,44 @@
if (mSmartspaceView != null) {
PropertyAnimator.setProperty(mSmartspaceView, AnimatableProperty.TRANSLATION_X,
x, props, animate);
+
+ // If we're unlocking with the SmartSpace shared element transition, let the controller
+ // know that it should re-position our SmartSpace.
+ if (mKeyguardUnlockAnimationController.isUnlockingWithSmartSpaceTransition()) {
+ mKeyguardUnlockAnimationController.updateLockscreenSmartSpacePosition();
+ } else {
+ // Otherwise, reset Y translation in case it's still offset from a previous shared
+ // element transition.
+ ((View) mSmartspaceView).setTranslationY(0f);
+ }
}
mKeyguardSliceViewController.updatePosition(x, props, animate);
mNotificationIconAreaController.updatePosition(x, props, animate);
}
+ /** Sets an alpha value on every child view except for the smartspace. */
+ public void setChildrenAlphaExcludingSmartspace(float alpha) {
+ final Set<View> excludedViews = new HashSet<>();
+
+ if (mSmartspaceView != null) {
+ excludedViews.add(mSmartspaceView);
+ }
+
+ setChildrenAlphaExcluding(alpha, excludedViews);
+ }
+
+ /** Sets an alpha value on every child view except for the views in the provided set. */
+ public void setChildrenAlphaExcluding(float alpha, Set<View> excludedViews) {
+ for (int i = 0; i < mView.getChildCount(); i++) {
+ final View child = mView.getChildAt(i);
+
+ if (!excludedViews.contains(child)) {
+ child.setAlpha(alpha);
+ }
+ }
+ }
+
void updateTimeZone(TimeZone timeZone) {
mView.onTimeZoneChanged(timeZone);
if (mClockViewController != null) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 299eceb..96eda3d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -28,6 +28,7 @@
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.GridLayout;
import android.widget.TextView;
@@ -39,6 +40,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.Set;
/**
* View consisting of:
@@ -55,6 +57,7 @@
private final LockPatternUtils mLockPatternUtils;
private final IActivityManager mIActivityManager;
+ private ViewGroup mStatusViewContainer;
private TextView mLogoutView;
private KeyguardClockSwitch mClockView;
private TextView mOwnerInfo;
@@ -66,6 +69,7 @@
private float mDarkAmount = 0;
private int mTextColor;
+ private float mChildrenAlphaExcludingSmartSpace = 1f;
/**
* Bottom margin that defines the margin between bottom of smart space and top of notification
@@ -132,6 +136,7 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ mStatusViewContainer = findViewById(R.id.status_view_container);
mLogoutView = findViewById(R.id.logout);
if (mLogoutView != null) {
mLogoutView.setOnClickListener(this::onLogoutClicked);
@@ -249,6 +254,27 @@
mClockView.setTextColor(blendedTextColor);
}
+ public void setChildrenAlphaExcludingClockView(float alpha) {
+ setChildrenAlphaExcluding(alpha, Set.of(mClockView));
+ }
+
+ /** Sets an alpha value on every view except for the views in the provided set. */
+ public void setChildrenAlphaExcluding(float alpha, Set<View> excludedViews) {
+ mChildrenAlphaExcludingSmartSpace = alpha;
+
+ for (int i = 0; i < mStatusViewContainer.getChildCount(); i++) {
+ final View child = mStatusViewContainer.getChildAt(i);
+
+ if (!excludedViews.contains(child)) {
+ child.setAlpha(alpha);
+ }
+ }
+ }
+
+ public float getChildrenAlphaExcludingSmartSpace() {
+ return mChildrenAlphaExcludingSmartSpace;
+ }
+
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("KeyguardStatusView:");
pw.println(" mOwnerInfo: " + (mOwnerInfo == null
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 388c085..7b6514a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -20,6 +20,8 @@
import android.os.UserHandle;
import android.util.Slog;
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
@@ -49,6 +51,9 @@
private final ConfigurationController mConfigurationController;
private final DozeParameters mDozeParameters;
private final KeyguardVisibilityHelper mKeyguardVisibilityHelper;
+ private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ private final KeyguardStateController mKeyguardStateController;
+ private SmartspaceTransitionController mSmartspaceTransitionController;
private final Rect mClipBounds = new Rect();
@Inject
@@ -59,15 +64,33 @@
KeyguardStateController keyguardStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
ConfigurationController configurationController,
- DozeParameters dozeParameters) {
+ DozeParameters dozeParameters,
+ KeyguardUnlockAnimationController keyguardUnlockAnimationController,
+ SmartspaceTransitionController smartspaceTransitionController) {
super(keyguardStatusView);
mKeyguardSliceViewController = keyguardSliceViewController;
mKeyguardClockSwitchController = keyguardClockSwitchController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mConfigurationController = configurationController;
mDozeParameters = dozeParameters;
+ mKeyguardStateController = keyguardStateController;
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, keyguardStateController,
dozeParameters);
+ mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
+ mSmartspaceTransitionController = smartspaceTransitionController;
+
+ mKeyguardStateController.addCallback(new KeyguardStateController.Callback() {
+ @Override
+ public void onKeyguardShowingChanged() {
+ // If we explicitly re-show the keyguard, make sure that all the child views are
+ // visible. They might have been animating out as part of the SmartSpace shared
+ // element transition.
+ if (keyguardStateController.isShowing()) {
+ mView.setChildrenAlphaExcludingClockView(1f);
+ mKeyguardClockSwitchController.setChildrenAlphaExcludingSmartspace(1f);
+ }
+ }
+ });
}
@Override
@@ -137,7 +160,24 @@
*/
public void setAlpha(float alpha) {
if (!mKeyguardVisibilityHelper.isVisibilityAnimating()) {
- mView.setAlpha(alpha);
+ // If we're capable of performing the SmartSpace shared element transition, and we are
+ // going to (we're swiping to dismiss vs. bringing up the PIN screen), then fade out
+ // everything except for the SmartSpace.
+ if (mKeyguardUnlockAnimationController.isUnlockingWithSmartSpaceTransition()) {
+ mView.setChildrenAlphaExcludingClockView(alpha);
+ mKeyguardClockSwitchController.setChildrenAlphaExcludingSmartspace(alpha);
+ } else if (!mKeyguardVisibilityHelper.isVisibilityAnimating()) {
+ // Otherwise, we can just set the alpha for the entire container.
+ mView.setAlpha(alpha);
+
+ // If we previously unlocked with the shared element transition, some child views
+ // might still have alpha = 0f. Set them back to 1f since we're just using the
+ // parent container's alpha.
+ if (mView.getChildrenAlphaExcludingSmartSpace() < 1f) {
+ mView.setChildrenAlphaExcludingClockView(1f);
+ mKeyguardClockSwitchController.setChildrenAlphaExcludingSmartspace(1f);
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
index 096597a..0d31906 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
@@ -16,22 +16,36 @@
package com.android.keyguard;
import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
+import android.graphics.drawable.VectorDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
+import androidx.annotation.Nullable;
+
+import com.android.settingslib.Utils;
+import com.android.systemui.R;
+
/**
* Similar to the {@link NumPadKey}, but displays an image.
*/
public class NumPadButton extends AlphaOptimizedImageButton {
+ @Nullable
private NumPadAnimator mAnimator;
public NumPadButton(Context context, AttributeSet attrs) {
super(context, attrs);
- mAnimator = new NumPadAnimator(context, (RippleDrawable) getBackground(),
- attrs.getStyleAttribute());
+ Drawable background = getBackground();
+ if (background instanceof RippleDrawable) {
+ mAnimator = new NumPadAnimator(context, (RippleDrawable) getBackground(),
+ attrs.getStyleAttribute());
+ } else {
+ mAnimator = null;
+ }
}
@Override
@@ -41,7 +55,7 @@
// Set width/height to the same value to ensure a smooth circle for the bg, but shrink
// the height to match the old pin bouncer
int width = getMeasuredWidth();
- int height = width;
+ int height = mAnimator == null ? (int) (width * .75f) : width;
setMeasuredDimension(getMeasuredWidth(), height);
}
@@ -50,12 +64,12 @@
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
- mAnimator.onLayout(b - t);
+ if (mAnimator != null) mAnimator.onLayout(b - t);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
- if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN && mAnimator != null) {
mAnimator.start();
}
return super.onTouchEvent(event);
@@ -65,6 +79,13 @@
* Reload colors from resources.
**/
public void reloadColors() {
- mAnimator.reloadColors(getContext());
+ if (mAnimator != null) {
+ mAnimator.reloadColors(getContext());
+ } else {
+ // Needed for old style pin
+ int textColor = Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary)
+ .getDefaultColor();
+ ((VectorDrawable) getDrawable()).setTintList(ColorStateList.valueOf(textColor));
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 35ace0d..cffa630 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
import android.os.PowerManager;
import android.os.SystemClock;
@@ -30,6 +31,8 @@
import android.view.accessibility.AccessibilityManager;
import android.widget.TextView;
+import androidx.annotation.Nullable;
+
import com.android.internal.widget.LockPatternUtils;
import com.android.settingslib.Utils;
import com.android.systemui.R;
@@ -47,6 +50,7 @@
private int mTextViewResId;
private PasswordTextView mTextView;
+ @Nullable
private NumPadAnimator mAnimator;
private View.OnClickListener mListener = new View.OnClickListener() {
@@ -126,8 +130,13 @@
setContentDescription(mDigitText.getText().toString());
- mAnimator = new NumPadAnimator(context, (RippleDrawable) getBackground(),
- R.style.NumPadKey);
+ Drawable background = getBackground();
+ if (background instanceof RippleDrawable) {
+ mAnimator = new NumPadAnimator(context, (RippleDrawable) background,
+ R.style.NumPadKey);
+ } else {
+ mAnimator = null;
+ }
}
/**
@@ -141,14 +150,14 @@
mDigitText.setTextColor(textColor);
mKlondikeText.setTextColor(klondikeColor);
- mAnimator.reloadColors(getContext());
+ if (mAnimator != null) mAnimator.reloadColors(getContext());
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
doHapticKeyClick();
- mAnimator.start();
+ if (mAnimator != null) mAnimator.start();
}
return super.onTouchEvent(event);
@@ -162,7 +171,7 @@
// Set width/height to the same value to ensure a smooth circle for the bg, but shrink
// the height to match the old pin bouncer
int width = getMeasuredWidth();
- int height = width;
+ int height = mAnimator == null ? (int) (width * .75f) : width;
setMeasuredDimension(getMeasuredWidth(), height);
}
@@ -183,7 +192,7 @@
left = centerX - mKlondikeText.getMeasuredWidth() / 2;
mKlondikeText.layout(left, top, left + mKlondikeText.getMeasuredWidth(), bottom);
- mAnimator.onLayout(b - t);
+ if (mAnimator != null) mAnimator.onLayout(b - t);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index afda2a4..e9c5653 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -236,7 +236,7 @@
Log.i(TAG, "ScreenDecorations is disabled");
return;
}
- mHandler = mThreadFactory.builderHandlerOnNewThread("ScreenDecorations");
+ mHandler = mThreadFactory.buildHandlerOnNewThread("ScreenDecorations");
mExecutor = mThreadFactory.buildDelayableExecutorOnHandler(mHandler);
mExecutor.execute(this::startOnScreenDecorationsThread);
mDotViewController.setUiExecutor(mExecutor);
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index cc167b9..e6fe060 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -133,6 +133,7 @@
.setTaskViewFactory(Optional.ofNullable(null))
.setTransitions(Transitions.createEmptyForTesting())
.setStartingSurface(Optional.ofNullable(null));
+
}
mSysUIComponent = builder.build();
if (mInitializeComponents) {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
index ee69e27..dba530e 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
@@ -40,6 +40,7 @@
private boolean mIsFalseRobustTap;
private final List<FalsingBeliefListener> mFalsingBeliefListeners = new ArrayList<>();
+ private final List<FalsingTapListener> mTapListeners = new ArrayList<>();
@Override
public void onSuccessfulUnlock() {
@@ -148,11 +149,15 @@
@Override
public void addTapListener(FalsingTapListener falsingTapListener) {
-
+ mTapListeners.add(falsingTapListener);
}
@Override
public void removeTapListener(FalsingTapListener falsingTapListener) {
+ mTapListeners.remove(falsingTapListener);
+ }
+ public List<FalsingTapListener> getTapListeners() {
+ return mTapListeners;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 26db33d..053d75d 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -46,6 +46,7 @@
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.media.AudioManager;
+import android.media.IAudioService;
import android.media.MediaRouter2Manager;
import android.media.session.MediaSessionManager;
import android.net.ConnectivityManager;
@@ -77,6 +78,8 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.shared.system.PackageManagerWrapper;
+import java.util.Optional;
+
import javax.inject.Singleton;
import dagger.Module;
@@ -167,6 +170,13 @@
@Provides
@Singleton
+ static IAudioService provideIAudioService() {
+ return IAudioService.Stub.asInterface(ServiceManager.getService(Context.AUDIO_SERVICE));
+ }
+
+
+ @Provides
+ @Singleton
static IBatteryStats provideIBatteryStats() {
return IBatteryStats.Stub.asInterface(
ServiceManager.getService(BatteryStats.SERVICE_NAME));
@@ -362,6 +372,12 @@
@Provides
@Singleton
+ static Optional<Vibrator> provideOptionalVibrator(Context context) {
+ return Optional.ofNullable(context.getSystemService(Vibrator.class));
+ }
+
+ @Provides
+ @Singleton
static ViewConfiguration provideViewConfiguration(Context context) {
return ViewConfiguration.get(context);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 1396099..f422e9e 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -45,6 +45,7 @@
import com.android.systemui.recents.Recents;
import com.android.systemui.screenshot.dagger.ScreenshotModule;
import com.android.systemui.settings.dagger.SettingsModule;
+import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -173,6 +174,12 @@
return SystemUIFactory.getInstance();
}
+ @SysUISingleton
+ @Provides
+ static SmartspaceTransitionController provideSmartspaceTransitionController() {
+ return new SmartspaceTransitionController();
+ }
+
// TODO: This should provided by the WM component
/** Provides Optional of BubbleManager */
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 411c328..665376a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -23,11 +23,14 @@
import android.graphics.Matrix
import android.view.RemoteAnimationTarget
import android.view.SyncRtSurfaceTransactionApplier
+import android.view.View
import androidx.core.math.MathUtils
import com.android.internal.R
+import com.android.keyguard.KeyguardClockSwitchController
import com.android.keyguard.KeyguardViewController
import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController
import com.android.systemui.statusbar.policy.KeyguardStateController
import dagger.Lazy
import javax.inject.Inject
@@ -85,7 +88,8 @@
context: Context,
private val keyguardStateController: KeyguardStateController,
private val keyguardViewMediator: Lazy<KeyguardViewMediator>,
- private val keyguardViewController: KeyguardViewController
+ private val keyguardViewController: KeyguardViewController,
+ private val smartspaceTransitionController: SmartspaceTransitionController
) : KeyguardStateController.Callback {
/**
@@ -131,6 +135,21 @@
/** Rounded corner radius to apply to the surface behind the keyguard. */
private var roundedCornerRadius = 0f
+ /** The SmartSpace view on the lockscreen, provided by [KeyguardClockSwitchController]. */
+ public var lockscreenSmartSpace: View? = null
+
+ /**
+ * Whether we are currently in the process of unlocking the keyguard, and we are performing the
+ * shared element SmartSpace transition.
+ */
+ private var unlockingWithSmartSpaceTransition: Boolean = false
+
+ /**
+ * Whether we tried to start the SmartSpace shared element transition for this unlock swipe.
+ * It's possible we're unable to do so (if the Launcher SmartSpace is not available).
+ */
+ private var attemptedSmartSpaceTransitionForThisSwipe = false
+
init {
surfaceBehindAlphaAnimator.duration = 150
surfaceBehindAlphaAnimator.interpolator = Interpolators.ALPHA_IN
@@ -214,6 +233,24 @@
}
/**
+ * Whether we are currently in the process of unlocking the keyguard, and we are performing the
+ * shared element SmartSpace transition.
+ */
+ fun isUnlockingWithSmartSpaceTransition(): Boolean {
+ return unlockingWithSmartSpaceTransition
+ }
+
+ /**
+ * Update the lockscreen SmartSpace to be positioned according to the current dismiss amount. As
+ * the dismiss amount increases, we will increase our SmartSpace's progress to the destination
+ * bounds (the location of the Launcher SmartSpace).
+ */
+ fun updateLockscreenSmartSpacePosition() {
+ smartspaceTransitionController.setProgressToDestinationBounds(
+ keyguardStateController.dismissAmount / DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD)
+ }
+
+ /**
* Scales in and translates up the surface behind the keyguard. This is used during unlock
* animations and swipe gestures to animate the surface's entry (and exit, if the swipe is
* cancelled).
@@ -284,36 +321,85 @@
return
}
+ if (keyguardViewController.isShowing) {
+ updateKeyguardViewMediatorIfThresholdsReached()
+
+ // If the surface is visible or it's about to be, start updating its appearance to
+ // reflect the new dismiss amount.
+ if (keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard() ||
+ keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe) {
+ updateSurfaceBehindAppearAmount()
+ }
+ }
+
+ // The end of the SmartSpace transition can occur after the keyguard is hidden (when we tell
+ // Launcher's SmartSpace to become visible again), so update it even if the keyguard view is
+ // no longer showing.
+ updateSmartSpaceTransition()
+ }
+
+ /**
+ * Lets the KeyguardViewMediator know if the dismiss amount has crossed a threshold of interest,
+ * such as reaching the point in the dismiss swipe where we need to make the surface behind the
+ * keyguard visible.
+ */
+ private fun updateKeyguardViewMediatorIfThresholdsReached() {
val dismissAmount = keyguardStateController.dismissAmount
// Hide the keyguard if we're fully dismissed, or if we're swiping to dismiss and have
// crossed the threshold to finish the dismissal.
val reachedHideKeyguardThreshold = (dismissAmount >= 1f ||
(keyguardStateController.isDismissingFromSwipe &&
- // Don't hide if we're flinging during a swipe, since we need to finish
- // animating it out. This will be called again after the fling ends.
- !keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture &&
- dismissAmount >= DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD))
+ // Don't hide if we're flinging during a swipe, since we need to finish
+ // animating it out. This will be called again after the fling ends.
+ !keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture &&
+ dismissAmount >= DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD))
if (dismissAmount >= DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD &&
!keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) {
- // We passed the threshold, and we're not yet showing the surface behind the keyguard.
- // Animate it in.
+ // We passed the threshold, and we're not yet showing the surface behind the
+ // keyguard. Animate it in.
keyguardViewMediator.get().showSurfaceBehindKeyguard()
fadeInSurfaceBehind()
} else if (dismissAmount < DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD &&
keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) {
- // We're no longer past the threshold but we are showing the surface. Animate it out.
+ // We're no longer past the threshold but we are showing the surface. Animate it
+ // out.
keyguardViewMediator.get().hideSurfaceBehindKeyguard()
fadeOutSurfaceBehind()
- } else if (keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe &&
+ } else if (keyguardViewMediator.get()
+ .isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe &&
reachedHideKeyguardThreshold) {
keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished()
}
+ }
- if (keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard() ||
- keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe) {
- updateSurfaceBehindAppearAmount()
+ /**
+ * Updates flags related to the SmartSpace transition in response to a change in keyguard
+ * dismiss amount, and also updates the SmartSpaceTransitionController, which will let Launcher
+ * know if it needs to do something as a result.
+ */
+ private fun updateSmartSpaceTransition() {
+ val dismissAmount = keyguardStateController.dismissAmount
+
+ // If we've begun a swipe, and are capable of doing the SmartSpace transition, start it!
+ if (!attemptedSmartSpaceTransitionForThisSwipe &&
+ dismissAmount > 0f &&
+ dismissAmount < 1f &&
+ keyguardViewController.isShowing) {
+ attemptedSmartSpaceTransitionForThisSwipe = true
+
+ smartspaceTransitionController.prepareForUnlockTransition()
+ if (keyguardStateController.canPerformSmartSpaceTransition()) {
+ unlockingWithSmartSpaceTransition = true
+ smartspaceTransitionController.launcherSmartspace?.setVisibility(
+ View.INVISIBLE)
+ }
+ } else if (attemptedSmartSpaceTransitionForThisSwipe &&
+ (dismissAmount == 0f || dismissAmount == 1f)) {
+ attemptedSmartSpaceTransitionForThisSwipe = false
+ unlockingWithSmartSpaceTransition = false
+ smartspaceTransitionController.launcherSmartspace?.setVisibility(View.VISIBLE)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index 73dfe5e..075bc70 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -26,21 +26,23 @@
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroupOverlay
+import androidx.annotation.VisibleForTesting
import com.android.systemui.R
import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.CrossFadeHelper
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.animation.UniqueObjectHostView
import javax.inject.Inject
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
/**
* Similarly to isShown but also excludes views that have 0 alpha
@@ -80,6 +82,7 @@
wakefulnessLifecycle: WakefulnessLifecycle,
private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager
) {
+
/**
* The root overlay of the hierarchy. This is where the media notification is attached to
* whenever the view is transitioning from one host to another. It also make sure that the
@@ -90,6 +93,30 @@
private var rootView: View? = null
private var currentBounds = Rect()
private var animationStartBounds: Rect = Rect()
+
+ /**
+ * The cross fade progress at the start of the animation. 0.5f means it's just switching between
+ * the start and the end location and the content is fully faded, while 0.75f means that we're
+ * halfway faded in again in the target state.
+ */
+ private var animationStartCrossFadeProgress = 0.0f
+
+ /**
+ * The starting alpha of the animation
+ */
+ private var animationStartAlpha = 0.0f
+
+ /**
+ * The starting location of the cross fade if an animation is running right now.
+ */
+ @MediaLocation
+ private var crossFadeAnimationStartLocation = -1
+
+ /**
+ * The end location of the cross fade if an animation is running right now.
+ */
+ @MediaLocation
+ private var crossFadeAnimationEndLocation = -1
private var targetBounds: Rect = Rect()
private val mediaFrame
get() = mediaCarouselController.mediaFrame
@@ -98,9 +125,22 @@
interpolator = Interpolators.FAST_OUT_SLOW_IN
addUpdateListener {
updateTargetState()
- interpolateBounds(animationStartBounds, targetBounds, animatedFraction,
+ val currentAlpha: Float
+ var boundsProgress = animatedFraction
+ if (isCrossFadeAnimatorRunning) {
+ animationCrossFadeProgress = MathUtils.lerp(animationStartCrossFadeProgress, 1.0f,
+ animatedFraction)
+ // When crossfading, let's keep the bounds at the right location during fading
+ boundsProgress = if (animationCrossFadeProgress < 0.5f) 0.0f else 1.0f
+ currentAlpha = calculateAlphaFromCrossFade(animationCrossFadeProgress,
+ instantlyShowAtEnd = false)
+ } else {
+ // If we're not crossfading, let's interpolate from the start alpha to 1.0f
+ currentAlpha = MathUtils.lerp(animationStartAlpha, 1.0f, animatedFraction)
+ }
+ interpolateBounds(animationStartBounds, targetBounds, boundsProgress,
result = currentBounds)
- applyState(currentBounds)
+ applyState(currentBounds, currentAlpha)
}
addListener(object : AnimatorListenerAdapter() {
private var cancelled: Boolean = false
@@ -112,6 +152,7 @@
}
override fun onAnimationEnd(animation: Animator?) {
+ isCrossFadeAnimatorRunning = false
if (!cancelled) {
applyTargetStateIfNotAnimating()
}
@@ -192,11 +233,6 @@
private var distanceForFullShadeTransition = 0
/**
- * Delay after which the media will start transitioning to the full shade on the lockscreen.
- */
- private var fullShadeTransitionDelay = 0
-
- /**
* The amount of progress we are currently in if we're transitioning to the full shade.
* 0.0f means we're not transitioning yet, while 1 means we're all the way in the full
* shade.
@@ -207,18 +243,33 @@
return
}
field = value
- if (bypassController.bypassEnabled) {
+ if (bypassController.bypassEnabled || statusbarState != StatusBarState.KEYGUARD) {
+ // No need to do all the calculations / updates below if we're not on the lockscreen
+ // or if we're bypassing.
return
}
- updateDesiredLocation()
+ updateDesiredLocation(forceNoAnimation = isCurrentlyFading())
if (value >= 0) {
updateTargetState()
+ // Setting the alpha directly, as the below call will use it to update the alpha
+ carouselAlpha = calculateAlphaFromCrossFade(field, instantlyShowAtEnd = true)
applyTargetStateIfNotAnimating()
}
}
+ /**
+ * Is there currently a cross-fade animation running driven by an animator?
+ */
+ private var isCrossFadeAnimatorRunning = false
+
+ /**
+ * Are we currently transitionioning from the lockscreen to the full shade
+ * [StatusBarState.SHADE_LOCKED] or [StatusBarState.SHADE]. Once the user has dragged down and
+ * the transition starts, this will no longer return true.
+ */
private val isTransitioningToFullShade: Boolean
- get() = fullShadeTransitionProgress != 0f && !bypassController.bypassEnabled
+ get() = fullShadeTransitionProgress != 0f && !bypassController.bypassEnabled &&
+ statusbarState == StatusBarState.KEYGUARD
/**
* Set the amount of pixels we have currently dragged down if we're transitioning to the full
@@ -227,14 +278,8 @@
fun setTransitionToFullShadeAmount(value: Float) {
// If we're transitioning starting on the shade_locked, we don't want any delay and rather
// have it aligned with the rest of the animation
- val delay = if (statusbarState == StatusBarState.KEYGUARD) {
- fullShadeTransitionDelay
- } else {
- 0
- }
- val progress = MathUtils.saturate((value - delay) /
- (distanceForFullShadeTransition - delay))
- fullShadeTransitionProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(progress)
+ val progress = MathUtils.saturate(value / distanceForFullShadeTransition)
+ fullShadeTransitionProgress = progress
}
/**
@@ -296,6 +341,49 @@
}
}
+ /**
+ * The current cross fade progress. 0.5f means it's just switching
+ * between the start and the end location and the content is fully faded, while 0.75f means
+ * that we're halfway faded in again in the target state.
+ * This is only valid while [isCrossFadeAnimatorRunning] is true.
+ */
+ private var animationCrossFadeProgress = 1.0f
+
+ /**
+ * The current carousel Alpha.
+ */
+ private var carouselAlpha: Float = 1.0f
+ set(value) {
+ if (field == value) {
+ return
+ }
+ field = value
+ CrossFadeHelper.fadeIn(mediaFrame, value)
+ }
+
+ /**
+ * Calculate the alpha of the view when given a cross-fade progress.
+ *
+ * @param crossFadeProgress The current cross fade progress. 0.5f means it's just switching
+ * between the start and the end location and the content is fully faded, while 0.75f means
+ * that we're halfway faded in again in the target state.
+ *
+ * @param instantlyShowAtEnd should the view be instantly shown at the end. This is needed
+ * to avoid fadinging in when the target was hidden anyway.
+ */
+ private fun calculateAlphaFromCrossFade(
+ crossFadeProgress: Float,
+ instantlyShowAtEnd: Boolean
+ ): Float {
+ if (crossFadeProgress <= 0.5f) {
+ return 1.0f - crossFadeProgress / 0.5f
+ } else if (instantlyShowAtEnd) {
+ return 1.0f
+ } else {
+ return (crossFadeProgress - 0.5f) / 0.5f
+ }
+ }
+
init {
updateConfiguration()
configurationController.addCallback(object : ConfigurationController.ConfigurationListener {
@@ -375,9 +463,7 @@
private fun updateConfiguration() {
distanceForFullShadeTransition = context.resources.getDimensionPixelSize(
- R.dimen.lockscreen_shade_qs_transition_distance)
- fullShadeTransitionDelay = context.resources.getDimensionPixelSize(
- R.dimen.lockscreen_shade_media_transition_start_delay)
+ R.dimen.lockscreen_shade_media_transition_distance)
}
/**
@@ -449,8 +535,13 @@
shouldAnimateTransition(desiredLocation, previousLocation)
val (animDuration, delay) = getAnimationParams(previousLocation, desiredLocation)
val host = getHost(desiredLocation)
- mediaCarouselController.onDesiredLocationChanged(desiredLocation, host, animate,
- animDuration, delay)
+ val willFade = calculateTransformationType() == TRANSFORMATION_TYPE_FADE
+ if (!willFade || isCurrentlyInGuidedTransformation() || !animate) {
+ // if we're fading, we want the desired location / measurement only to change
+ // once fully faded. This is happening in the host attachment
+ mediaCarouselController.onDesiredLocationChanged(desiredLocation, host,
+ animate, animDuration, delay)
+ }
performTransitionToNewLocation(isNewView, animate)
}
}
@@ -470,6 +561,8 @@
if (isCurrentlyInGuidedTransformation()) {
applyTargetStateIfNotAnimating()
} else if (animate) {
+ val wasCrossFading = isCrossFadeAnimatorRunning
+ val previewsCrossFadeProgress = animationCrossFadeProgress
animator.cancel()
if (currentAttachmentLocation != previousLocation ||
!previousHost.hostView.isAttachedToWindow) {
@@ -482,6 +575,42 @@
// be outdated
animationStartBounds.set(previousHost.currentBounds)
}
+ val transformationType = calculateTransformationType()
+ var needsCrossFade = transformationType == TRANSFORMATION_TYPE_FADE
+ var crossFadeStartProgress = 0.0f
+ // The alpha is only relevant when not cross fading
+ var newCrossFadeStartLocation = previousLocation
+ if (wasCrossFading) {
+ if (currentAttachmentLocation == crossFadeAnimationEndLocation) {
+ if (needsCrossFade) {
+ // We were previously crossFading and we've already reached
+ // the end view, Let's start crossfading from the same position there
+ crossFadeStartProgress = 1.0f - previewsCrossFadeProgress
+ }
+ // Otherwise let's fade in from the current alpha, but not cross fade
+ } else {
+ // We haven't reached the previous location yet, let's still cross fade from
+ // where we were.
+ newCrossFadeStartLocation = crossFadeAnimationStartLocation
+ if (newCrossFadeStartLocation == desiredLocation) {
+ // we're crossFading back to where we were, let's start at the end position
+ crossFadeStartProgress = 1.0f - previewsCrossFadeProgress
+ } else {
+ // Let's start from where we are right now
+ crossFadeStartProgress = previewsCrossFadeProgress
+ // We need to force cross fading as we haven't reached the end location yet
+ needsCrossFade = true
+ }
+ }
+ } else if (needsCrossFade) {
+ // let's not flicker and start with the same alpha
+ crossFadeStartProgress = (1.0f - carouselAlpha) / 2.0f
+ }
+ isCrossFadeAnimatorRunning = needsCrossFade
+ crossFadeAnimationStartLocation = newCrossFadeStartLocation
+ crossFadeAnimationEndLocation = desiredLocation
+ animationStartAlpha = carouselAlpha
+ animationStartCrossFadeProgress = crossFadeStartProgress
adjustAnimatorForTransition(desiredLocation, previousLocation)
if (!animationPending) {
rootView?.let {
@@ -518,6 +647,17 @@
// non-trivial reattaching logic happening that will make the view not-shown earlier
return true
}
+
+ if (statusbarState == StatusBarState.KEYGUARD) {
+ if (currentLocation == LOCATION_LOCKSCREEN &&
+ previousLocation == LOCATION_QS ||
+ (currentLocation == LOCATION_QS &&
+ previousLocation == LOCATION_LOCKSCREEN)) {
+ // We're always fading from lockscreen to keyguard in situations where the player
+ // is already fully hidden
+ return false
+ }
+ }
return mediaFrame.isShownNotFaded || animator.isRunning || animationPending
}
@@ -538,7 +678,7 @@
keyguardStateController.isKeyguardFadingAway) {
delay = keyguardStateController.keyguardFadingAwayDelay
}
- animDuration = StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE.toLong()
+ animDuration = (StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE / 2f).toLong()
} else if (previousLocation == LOCATION_QQS && desiredLocation == LOCATION_LOCKSCREEN) {
animDuration = StackStateAnimator.ANIMATION_DURATION_APPEAR_DISAPPEAR.toLong()
}
@@ -550,7 +690,7 @@
// Let's immediately apply the target state (which is interpolated) if there is
// no animation running. Otherwise the animation update will already update
// the location
- applyState(targetBounds)
+ applyState(targetBounds, carouselAlpha)
}
}
@@ -558,7 +698,7 @@
* Updates the bounds that the view wants to be in at the end of the animation.
*/
private fun updateTargetState() {
- if (isCurrentlyInGuidedTransformation()) {
+ if (isCurrentlyInGuidedTransformation() && !isCurrentlyFading()) {
val progress = getTransformationProgress()
var endHost = getHost(desiredLocation)!!
var starthost = getHost(previousLocation)!!
@@ -606,12 +746,33 @@
}
/**
+ * Calculate the transformation type for the current animation
+ */
+ @VisibleForTesting
+ @TransformationType
+ fun calculateTransformationType(): Int {
+ if (isTransitioningToFullShade) {
+ return TRANSFORMATION_TYPE_FADE
+ }
+ if (previousLocation == LOCATION_LOCKSCREEN && desiredLocation == LOCATION_QS ||
+ previousLocation == LOCATION_QS && desiredLocation == LOCATION_LOCKSCREEN) {
+ // animating between ls and qs should fade, as QS is clipped.
+ return TRANSFORMATION_TYPE_FADE
+ }
+ if (previousLocation == LOCATION_LOCKSCREEN && desiredLocation == LOCATION_QQS) {
+ // animating between ls and qqs should fade when dragging down via e.g. expand button
+ return TRANSFORMATION_TYPE_FADE
+ }
+ return TRANSFORMATION_TYPE_TRANSITION
+ }
+
+ /**
* @return the current transformation progress if we're in a guided transformation and -1
* otherwise
*/
private fun getTransformationProgress(): Float {
val progress = getQSTransformationProgress()
- if (progress >= 0) {
+ if (statusbarState != StatusBarState.KEYGUARD && progress >= 0) {
return progress
}
if (isTransitioningToFullShade) {
@@ -643,19 +804,20 @@
private fun cancelAnimationAndApplyDesiredState() {
animator.cancel()
getHost(desiredLocation)?.let {
- applyState(it.currentBounds, immediately = true)
+ applyState(it.currentBounds, alpha = 1.0f, immediately = true)
}
}
/**
* Apply the current state to the view, updating it's bounds and desired state
*/
- private fun applyState(bounds: Rect, immediately: Boolean = false) {
+ private fun applyState(bounds: Rect, alpha: Float, immediately: Boolean = false) {
currentBounds.set(bounds)
- val currentlyInGuidedTransformation = isCurrentlyInGuidedTransformation()
- val startLocation = if (currentlyInGuidedTransformation) previousLocation else -1
- val progress = if (currentlyInGuidedTransformation) getTransformationProgress() else 1.0f
- val endLocation = desiredLocation
+ carouselAlpha = if (isCurrentlyFading()) alpha else 1.0f
+ val onlyUseEndState = !isCurrentlyInGuidedTransformation() || isCurrentlyFading()
+ val startLocation = if (onlyUseEndState) -1 else previousLocation
+ val progress = if (onlyUseEndState) 1.0f else getTransformationProgress()
+ val endLocation = resolveLocationForFading()
mediaCarouselController.setCurrentState(startLocation, endLocation, progress, immediately)
updateHostAttachment()
if (currentAttachmentLocation == IN_OVERLAY) {
@@ -668,8 +830,19 @@
}
private fun updateHostAttachment() {
- val inOverlay = isTransitionRunning() && rootOverlay != null
- val newLocation = if (inOverlay) IN_OVERLAY else desiredLocation
+ var newLocation = resolveLocationForFading()
+ var canUseOverlay = !isCurrentlyFading()
+ if (isCrossFadeAnimatorRunning) {
+ if (getHost(newLocation)?.visible == true &&
+ getHost(newLocation)?.hostView?.isShown == false &&
+ newLocation != desiredLocation) {
+ // We're crossfading but the view is already hidden. Let's move to the overlay
+ // instead. This happens when animating to the full shade using a button click.
+ canUseOverlay = true
+ }
+ }
+ val inOverlay = isTransitionRunning() && rootOverlay != null && canUseOverlay
+ newLocation = if (inOverlay) IN_OVERLAY else newLocation
if (currentAttachmentLocation != newLocation) {
currentAttachmentLocation = newLocation
@@ -677,10 +850,10 @@
(mediaFrame.parent as ViewGroup?)?.removeView(mediaFrame)
// Add it to the new one
- val targetHost = getHost(desiredLocation)!!.hostView
if (inOverlay) {
rootOverlay!!.add(mediaFrame)
} else {
+ val targetHost = getHost(newLocation)!!.hostView
// When adding back to the host, let's make sure to reset the bounds.
// Usually adding the view will trigger a layout that does this automatically,
// but we sometimes suppress this.
@@ -693,9 +866,39 @@
left + currentBounds.width(),
top + currentBounds.height())
}
+ if (isCrossFadeAnimatorRunning) {
+ // When cross-fading with an animation, we only notify the media carousel of the
+ // location change, once the view is reattached to the new place and not immediately
+ // when the desired location changes. This callback will update the measurement
+ // of the carousel, only once we've faded out at the old location and then reattach
+ // to fade it in at the new location.
+ mediaCarouselController.onDesiredLocationChanged(
+ newLocation,
+ getHost(newLocation),
+ animate = false
+ )
+ }
}
}
+ /**
+ * Calculate the location when cross fading between locations. While fading out,
+ * the content should remain in the previous location, while after the switch it should
+ * be at the desired location.
+ */
+ private fun resolveLocationForFading(): Int {
+ if (isCrossFadeAnimatorRunning) {
+ // When animating between two hosts with a fade, let's keep ourselves in the old
+ // location for the first half, and then switch over to the end location
+ if (animationCrossFadeProgress > 0.5 || previousLocation == -1) {
+ return crossFadeAnimationEndLocation
+ } else {
+ return crossFadeAnimationStartLocation
+ }
+ }
+ return desiredLocation
+ }
+
private fun isTransitionRunning(): Boolean {
return isCurrentlyInGuidedTransformation() && getTransformationProgress() != 1.0f ||
animator.isRunning || animationPending
@@ -708,29 +911,29 @@
return desiredLocation
}
val onLockscreen = (!bypassController.bypassEnabled &&
- (statusbarState == StatusBarState.KEYGUARD ||
- statusbarState == StatusBarState.FULLSCREEN_USER_SWITCHER))
+ (statusbarState == StatusBarState.KEYGUARD ||
+ statusbarState == StatusBarState.FULLSCREEN_USER_SWITCHER))
val allowedOnLockscreen = notifLockscreenUserManager.shouldShowLockscreenNotifications()
val location = when {
qsExpansion > 0.0f && !onLockscreen -> LOCATION_QS
qsExpansion > 0.4f && onLockscreen -> LOCATION_QS
- onLockscreen && isTransitioningToFullShade -> LOCATION_QQS
+ onLockscreen && isTransformingToFullShadeAndInQQS() -> LOCATION_QQS
onLockscreen && allowedOnLockscreen -> LOCATION_LOCKSCREEN
else -> LOCATION_QQS
}
// When we're on lock screen and the player is not active, we should keep it in QS.
// Otherwise it will try to animate a transition that doesn't make sense.
if (location == LOCATION_LOCKSCREEN && getHost(location)?.visible != true &&
- !statusBarStateController.isDozing) {
+ !statusBarStateController.isDozing) {
return LOCATION_QS
}
if (location == LOCATION_LOCKSCREEN && desiredLocation == LOCATION_QS &&
- collapsingShadeFromQS) {
+ collapsingShadeFromQS) {
// When collapsing on the lockscreen, we want to remain in QS
return LOCATION_QS
}
if (location != LOCATION_LOCKSCREEN && desiredLocation == LOCATION_LOCKSCREEN &&
- !fullyAwake) {
+ !fullyAwake) {
// When unlocking from dozing / while waking up, the media shouldn't be transitioning
// in an animated way. Let's keep it in the lockscreen until we're fully awake and
// reattach it without an animation
@@ -740,6 +943,26 @@
}
/**
+ * Are we currently transforming to the full shade and already in QQS
+ */
+ private fun isTransformingToFullShadeAndInQQS(): Boolean {
+ if (!isTransitioningToFullShade) {
+ return false
+ }
+ return fullShadeTransitionProgress > 0.5f
+ }
+
+ /**
+ * Is the current transformationType fading
+ */
+ private fun isCurrentlyFading(): Boolean {
+ if (isTransitioningToFullShade) {
+ return true
+ }
+ return isCrossFadeAnimatorRunning
+ }
+
+ /**
* Returns true when the media card could be visible to the user if existed.
*/
private fun isVisibleToUser(): Boolean {
@@ -789,9 +1012,27 @@
* Attached at the root of the hierarchy in an overlay
*/
const val IN_OVERLAY = -1000
+
+ /**
+ * The default transformation type where the hosts transform into each other using a direct
+ * transition
+ */
+ const val TRANSFORMATION_TYPE_TRANSITION = 0
+
+ /**
+ * A transformation type where content fades from one place to another instead of
+ * transitioning
+ */
+ const val TRANSFORMATION_TYPE_FADE = 1
}
}
+@IntDef(prefix = ["TRANSFORMATION_TYPE_"], value = [
+ MediaHierarchyManager.TRANSFORMATION_TYPE_TRANSITION,
+ MediaHierarchyManager.TRANSFORMATION_TYPE_FADE])
+@Retention(AnnotationRetention.SOURCE)
+private annotation class TransformationType
+
@IntDef(prefix = ["LOCATION_"], value = [MediaHierarchyManager.LOCATION_QS,
MediaHierarchyManager.LOCATION_QQS, MediaHierarchyManager.LOCATION_LOCKSCREEN])
@Retention(AnnotationRetention.SOURCE)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
index b0be576..3bf7fb0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
@@ -23,7 +23,6 @@
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.media.MediaDescription
-import android.media.session.MediaController
import android.os.UserHandle
import android.provider.Settings
import android.service.media.MediaBrowserService
@@ -171,6 +170,7 @@
if (useMediaResumption) {
// If this had been started from a resume state, disconnect now that it's live
mediaBrowser?.disconnect()
+ mediaBrowser = null
// If we don't have a resume action, check if we haven't already
if (data.resumeAction == null && !data.hasCheckedForResume &&
!blockedApps.contains(data.packageName) && data.isLocalSession) {
@@ -201,7 +201,6 @@
*/
private fun tryUpdateResumptionList(key: String, componentName: ComponentName) {
Log.d(TAG, "Testing if we can connect to $componentName")
- mediaBrowser?.disconnect()
mediaBrowser = mediaBrowserFactory.create(
object : ResumeMediaBrowser.Callback() {
override fun onConnected() {
@@ -211,7 +210,6 @@
override fun onError() {
Log.e(TAG, "Cannot resume with $componentName")
mediaDataManager.setResumeAction(key, null)
- mediaBrowser?.disconnect()
mediaBrowser = null
}
@@ -224,7 +222,6 @@
Log.d(TAG, "Can get resumable media from $componentName")
mediaDataManager.setResumeAction(key, getResumeAction(componentName))
updateResumptionList(componentName)
- mediaBrowser?.disconnect()
mediaBrowser = null
}
},
@@ -262,30 +259,7 @@
*/
private fun getResumeAction(componentName: ComponentName): Runnable {
return Runnable {
- mediaBrowser?.disconnect()
- mediaBrowser = mediaBrowserFactory.create(
- object : ResumeMediaBrowser.Callback() {
- override fun onConnected() {
- if (mediaBrowser?.token == null) {
- Log.e(TAG, "Error after connect")
- mediaBrowser?.disconnect()
- mediaBrowser = null
- return
- }
- Log.d(TAG, "Connected for restart $componentName")
- val controller = MediaController(context, mediaBrowser!!.token)
- val controls = controller.transportControls
- controls.prepare()
- controls.play()
- }
-
- override fun onError() {
- Log.e(TAG, "Resume failed for $componentName")
- mediaBrowser?.disconnect()
- mediaBrowser = null
- }
- },
- componentName)
+ mediaBrowser = mediaBrowserFactory.create(null, componentName)
mediaBrowser?.restart()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
index e453653..fecc903 100644
--- a/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
+++ b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
@@ -16,6 +16,7 @@
package com.android.systemui.media;
+import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -47,7 +48,7 @@
private static final String TAG = "ResumeMediaBrowser";
private final Context mContext;
- private final Callback mCallback;
+ @Nullable private final Callback mCallback;
private MediaBrowserFactory mBrowserFactory;
private MediaBrowser mMediaBrowser;
private ComponentName mComponentName;
@@ -58,8 +59,8 @@
* @param callback used to report media items found
* @param componentName Component name of the MediaBrowserService this browser will connect to
*/
- public ResumeMediaBrowser(Context context, Callback callback, ComponentName componentName,
- MediaBrowserFactory browserFactory) {
+ public ResumeMediaBrowser(Context context, @Nullable Callback callback,
+ ComponentName componentName, MediaBrowserFactory browserFactory) {
mContext = context;
mCallback = callback;
mComponentName = componentName;
@@ -93,18 +94,24 @@
List<MediaBrowser.MediaItem> children) {
if (children.size() == 0) {
Log.d(TAG, "No children found for " + mComponentName);
- mCallback.onError();
+ if (mCallback != null) {
+ mCallback.onError();
+ }
} else {
// We ask apps to return a playable item as the first child when sending
// a request with EXTRA_RECENT; if they don't, no resume controls
MediaBrowser.MediaItem child = children.get(0);
MediaDescription desc = child.getDescription();
if (child.isPlayable() && mMediaBrowser != null) {
- mCallback.addTrack(desc, mMediaBrowser.getServiceComponent(),
- ResumeMediaBrowser.this);
+ if (mCallback != null) {
+ mCallback.addTrack(desc, mMediaBrowser.getServiceComponent(),
+ ResumeMediaBrowser.this);
+ }
} else {
Log.d(TAG, "Child found but not playable for " + mComponentName);
- mCallback.onError();
+ if (mCallback != null) {
+ mCallback.onError();
+ }
}
}
disconnect();
@@ -113,7 +120,9 @@
@Override
public void onError(String parentId) {
Log.d(TAG, "Subscribe error for " + mComponentName + ": " + parentId);
- mCallback.onError();
+ if (mCallback != null) {
+ mCallback.onError();
+ }
disconnect();
}
@@ -121,7 +130,9 @@
public void onError(String parentId, Bundle options) {
Log.d(TAG, "Subscribe error for " + mComponentName + ": " + parentId
+ ", options: " + options);
- mCallback.onError();
+ if (mCallback != null) {
+ mCallback.onError();
+ }
disconnect();
}
};
@@ -138,13 +149,20 @@
Log.d(TAG, "Service connected for " + mComponentName);
if (mMediaBrowser != null && mMediaBrowser.isConnected()) {
String root = mMediaBrowser.getRoot();
- if (!TextUtils.isEmpty(root) && mMediaBrowser != null) {
- mCallback.onConnected();
- mMediaBrowser.subscribe(root, mSubscriptionCallback);
+ if (!TextUtils.isEmpty(root)) {
+ if (mCallback != null) {
+ mCallback.onConnected();
+ }
+ if (mMediaBrowser != null) {
+ mMediaBrowser.subscribe(root, mSubscriptionCallback);
+ }
return;
}
}
- mCallback.onError();
+ if (mCallback != null) {
+ mCallback.onError();
+ }
+ disconnect();
}
/**
@@ -153,7 +171,9 @@
@Override
public void onConnectionSuspended() {
Log.d(TAG, "Connection suspended for " + mComponentName);
- mCallback.onError();
+ if (mCallback != null) {
+ mCallback.onError();
+ }
disconnect();
}
@@ -163,16 +183,18 @@
@Override
public void onConnectionFailed() {
Log.d(TAG, "Connection failed for " + mComponentName);
- mCallback.onError();
+ if (mCallback != null) {
+ mCallback.onError();
+ }
disconnect();
}
};
/**
- * Disconnect the media browser. This should be called after restart or testConnection have
- * completed to close the connection.
+ * Disconnect the media browser. This should be done after callbacks have completed to
+ * disconnect from the media browser service.
*/
- public void disconnect() {
+ protected void disconnect() {
if (mMediaBrowser != null) {
mMediaBrowser.disconnect();
}
@@ -183,7 +205,8 @@
* Connects to the MediaBrowserService and starts playback.
* ResumeMediaBrowser.Callback#onError or ResumeMediaBrowser.Callback#onConnected will be called
* depending on whether it was successful.
- * ResumeMediaBrowser#disconnect should be called after this to ensure the connection is closed.
+ * If the connection is successful, the listener should call ResumeMediaBrowser#disconnect after
+ * getting a media update from the app
*/
public void restart() {
disconnect();
@@ -195,7 +218,10 @@
public void onConnected() {
Log.d(TAG, "Connected for restart " + mMediaBrowser.isConnected());
if (mMediaBrowser == null || !mMediaBrowser.isConnected()) {
- mCallback.onError();
+ if (mCallback != null) {
+ mCallback.onError();
+ }
+ disconnect();
return;
}
MediaSession.Token token = mMediaBrowser.getSessionToken();
@@ -203,17 +229,26 @@
controller.getTransportControls();
controller.getTransportControls().prepare();
controller.getTransportControls().play();
- mCallback.onConnected();
+ if (mCallback != null) {
+ mCallback.onConnected();
+ }
+ // listener should disconnect after media player update
}
@Override
public void onConnectionFailed() {
- mCallback.onError();
+ if (mCallback != null) {
+ mCallback.onError();
+ }
+ disconnect();
}
@Override
public void onConnectionSuspended() {
- mCallback.onError();
+ if (mCallback != null) {
+ mCallback.onError();
+ }
+ disconnect();
}
}, rootHints);
mMediaBrowser.connect();
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 9e77b60..d8b342a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -31,6 +31,7 @@
import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
@@ -200,7 +201,7 @@
private final UiEventLogger mUiEventLogger;
private Bundle mSavedState;
- private NavigationBarView mNavigationBarView = null;
+ private NavigationBarView mNavigationBarView;
private @WindowVisibleState int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
@@ -392,7 +393,8 @@
};
private final Runnable mAutoDim = () -> getBarTransitions().setAutoDim(true);
-
+ private final Runnable mEnableLayoutTransitions = () ->
+ mNavigationBarView.setLayoutTransitionsEnabled(true);
private final Runnable mOnVariableDurationHomeLongClick = () -> {
if (onHomeLongClick(mNavigationBarView.getHomeButton().getCurrentView())) {
mNavigationBarView.getHomeButton().getCurrentView().performHapticFeedback(
@@ -488,7 +490,7 @@
mA11yBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode();
}
- public View getView() {
+ public NavigationBarView getView() {
return mNavigationBarView;
}
@@ -504,16 +506,19 @@
| WindowManager.LayoutParams.FLAG_SLIPPERY,
PixelFormat.TRANSLUCENT);
lp.token = new Binder();
- lp.setTitle("NavigationBar" + mContext.getDisplayId());
lp.accessibilityTitle = mContext.getString(R.string.nav_bar);
- lp.windowAnimations = 0;
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
+ lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+ lp.windowAnimations = 0;
+ lp.setTitle("NavigationBar" + mContext.getDisplayId());
+ lp.setFitInsetsTypes(0 /* types */);
NavigationBarFrame frame = (NavigationBarFrame) LayoutInflater.from(mContext).inflate(
R.layout.navigation_bar_window, null);
View barView = LayoutInflater.from(frame.getContext()).inflate(
R.layout.navigation_bar, frame);
barView.addOnAttachStateChangeListener(this);
+ mNavigationBarView = barView.findViewById(R.id.navigation_bar_view);
if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + barView);
mContext.getSystemService(WindowManager.class).addView(frame, lp);
@@ -533,6 +538,19 @@
mContentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED),
false, mAssistContentObserver, UserHandle.USER_ALL);
+ mAllowForceNavBarHandleOpaque = mContext.getResources().getBoolean(
+ R.bool.allow_force_nav_bar_handle_opaque);
+ mForceNavBarHandleOpaque = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ NAV_BAR_HANDLE_FORCE_OPAQUE,
+ /* defaultValue = */ true);
+ mHomeButtonLongPressDurationMs = Optional.of(DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ HOME_BUTTON_LONG_PRESS_DURATION_MS,
+ /* defaultValue = */ 0
+ )).filter(duration -> duration != 0);
+ DeviceConfig.addOnPropertiesChangedListener(
+ DeviceConfig.NAMESPACE_SYSTEMUI, mHandler::post, mOnPropertiesChangedListener);
updateAssistantEntrypoints();
if (savedState != null) {
@@ -543,25 +561,10 @@
mTransientShown = savedState.getBoolean(EXTRA_TRANSIENT_STATE, false);
}
mSavedState = savedState;
- mAccessibilityManagerWrapper.addCallback(mAccessibilityListener);
// Respect the latest disabled-flags.
mCommandQueue.recomputeDisableFlags(mDisplayId, false);
- mAllowForceNavBarHandleOpaque = mContext.getResources().getBoolean(
- R.bool.allow_force_nav_bar_handle_opaque);
- mForceNavBarHandleOpaque = DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_SYSTEMUI,
- NAV_BAR_HANDLE_FORCE_OPAQUE,
- /* defaultValue = */ true);
- mHomeButtonLongPressDurationMs = Optional.of(DeviceConfig.getLong(
- DeviceConfig.NAMESPACE_SYSTEMUI,
- HOME_BUTTON_LONG_PRESS_DURATION_MS,
- /* defaultValue = */ 0
- )).filter(duration -> duration != 0);
- DeviceConfig.addOnPropertiesChangedListener(
- DeviceConfig.NAMESPACE_SYSTEMUI, mHandler::post, mOnPropertiesChangedListener);
-
mIsCurrentUserSetup = mDeviceProvisionedController.isCurrentUserSetup();
mDeviceProvisionedController.addCallback(mUserSetupListener);
@@ -587,7 +590,6 @@
@Override
public void onViewAttachedToWindow(View v) {
final Display display = v.getDisplay();
- mNavigationBarView = v.findViewById(R.id.navigation_bar_view);
mNavigationBarView.setComponents(mStatusBarLazy.get().getPanelController());
mNavigationBarView.setDisabledFlags(mDisabledFlags1);
mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);
@@ -598,6 +600,9 @@
mNavigationBarView.setNavigationIconHints(mNavigationIconHints);
mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
mNavigationBarView.setBehavior(mBehavior);
+
+ mAccessibilityManagerWrapper.addCallback(mAccessibilityListener);
+
mSplitScreenOptional.ifPresent(mNavigationBarView::registerDockedListener);
mPipOptional.ifPresent(mNavigationBarView::registerPipExclusionBoundsChangeListener);
@@ -657,10 +662,8 @@
@Override
public void onViewDetachedFromWindow(View v) {
- if (mNavigationBarView != null) {
- mNavigationBarView.getBarTransitions().destroy();
- mNavigationBarView.getLightTransitionsController().destroy(mContext);
- }
+ mNavigationBarView.getBarTransitions().destroy();
+ mNavigationBarView.getLightTransitionsController().destroy(mContext);
mOverviewProxyService.removeCallback(mOverviewProxyListener);
mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
if (mOrientationHandle != null) {
@@ -671,6 +674,8 @@
mOrientationHandleGlobalLayoutListener);
}
mHandler.removeCallbacks(mAutoDim);
+ mHandler.removeCallbacks(mOnVariableDurationHomeLongClick);
+ mHandler.removeCallbacks(mEnableLayoutTransitions);
mNavigationBarView = null;
mOrientationHandle = null;
}
@@ -682,9 +687,7 @@
outState.putInt(EXTRA_APPEARANCE, mAppearance);
outState.putInt(EXTRA_BEHAVIOR, mBehavior);
outState.putBoolean(EXTRA_TRANSIENT_STATE, mTransientShown);
- if (mNavigationBarView != null) {
- mNavigationBarView.getLightTransitionsController().saveState(outState);
- }
+ mNavigationBarView.getLightTransitionsController().saveState(outState);
}
/**
@@ -809,15 +812,12 @@
// mOrientedHandle is initialized lazily
mOrientationHandle.setVisibility(View.GONE);
}
- if (mNavigationBarView != null) {
- mNavigationBarView.setVisibility(View.VISIBLE);
- mNavigationBarView.setOrientedHandleSamplingRegion(null);
- }
+ mNavigationBarView.setVisibility(View.VISIBLE);
+ mNavigationBarView.setOrientedHandleSamplingRegion(null);
}
private void reconfigureHomeLongClick() {
- if (mNavigationBarView == null
- || mNavigationBarView.getHomeButton().getCurrentView() == null) {
+ if (mNavigationBarView.getHomeButton().getCurrentView() == null) {
return;
}
if (mHomeButtonLongPressDurationMs.isPresent() || !mLongPressHomeEnabled) {
@@ -844,17 +844,12 @@
pw.println(" mHomeButtonLongPressDurationMs=" + mHomeButtonLongPressDurationMs);
pw.println(" mLongPressHomeEnabled=" + mLongPressHomeEnabled);
pw.println(" mAssistantTouchGestureEnabled=" + mAssistantTouchGestureEnabled);
-
- if (mNavigationBarView != null) {
- pw.println(" mNavigationBarWindowState="
- + windowStateToString(mNavigationBarWindowState));
- pw.println(" mNavigationBarMode="
- + BarTransitions.modeToString(mNavigationBarMode));
- dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions());
- mNavigationBarView.dump(pw);
- } else {
- pw.print(" mNavigationBarView=null");
- }
+ pw.println(" mNavigationBarWindowState="
+ + windowStateToString(mNavigationBarWindowState));
+ pw.println(" mNavigationBarMode="
+ + BarTransitions.modeToString(mNavigationBarMode));
+ dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions());
+ mNavigationBarView.dump(pw);
}
// ----- CommandQueue Callbacks -----
@@ -889,10 +884,7 @@
if (hints == mNavigationIconHints) return;
mNavigationIconHints = hints;
-
- if (mNavigationBarView != null) {
- mNavigationBarView.setNavigationIconHints(hints);
- }
+ mNavigationBarView.setNavigationIconHints(hints);
checkBarModes();
updateSystemUiStateFlags(-1);
}
@@ -911,23 +903,12 @@
orientSecondaryHomeHandle();
}
if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));
-
- if (mNavigationBarView != null) {
- mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
- }
+ mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
}
}
@Override
public void onRotationProposal(final int rotation, boolean isValid) {
- if (mNavigationBarView == null) {
- if (RotationContextButton.DEBUG_ROTATION) {
- Log.v(TAG, "onRotationProposal proposedRotation=" +
- Surface.rotationToString(rotation) + ", mNavigationBarView is null");
- }
- return;
- }
-
final int winRotation = mNavigationBarView.getDisplay().getRotation();
final boolean rotateSuggestionsDisabled = RotationButtonController
.hasDisable2RotateSuggestionFlag(mDisabledFlags2);
@@ -941,8 +922,7 @@
+ ", isValid=" + isValid + ", mNavBarWindowState="
+ StatusBarManager.windowStateToString(mNavigationBarWindowState)
+ ", rotateSuggestionsDisabled=" + rotateSuggestionsDisabled
- + ", isRotateButtonVisible=" + (mNavigationBarView == null ? "null"
- : rotationButton.isVisible()));
+ + ", isRotateButtonVisible=" + rotationButton.isVisible());
}
// Respect the disabled flag, no need for action as flag change callback will handle hiding
@@ -983,9 +963,6 @@
boolean nbModeChanged = false;
if (mAppearance != appearance) {
mAppearance = appearance;
- if (getView() == null) {
- return;
- }
nbModeChanged = updateBarMode(barMode(mTransientShown, appearance));
}
if (mLightBarController != null) {
@@ -994,9 +971,7 @@
}
if (mBehavior != behavior) {
mBehavior = behavior;
- if (mNavigationBarView != null) {
- mNavigationBarView.setBehavior(behavior);
- }
+ mNavigationBarView.setBehavior(behavior);
updateSystemUiStateFlags(-1);
}
}
@@ -1034,12 +1009,7 @@
}
private void handleTransientChanged() {
- if (getView() == null) {
- return;
- }
- if (mNavigationBarView != null) {
- mNavigationBarView.onTransientStateChanged(mTransientShown);
- }
+ mNavigationBarView.onTransientStateChanged(mTransientShown);
final int barMode = barMode(mTransientShown, mAppearance);
if (updateBarMode(barMode) && mLightBarController != null) {
mLightBarController.onNavigationBarModeChanged(barMode);
@@ -1092,9 +1062,7 @@
| StatusBarManager.DISABLE_SEARCH);
if (masked != mDisabledFlags1) {
mDisabledFlags1 = masked;
- if (mNavigationBarView != null) {
- mNavigationBarView.setDisabledFlags(state1);
- }
+ mNavigationBarView.setDisabledFlags(state1);
updateScreenPinningGestures();
}
@@ -1110,17 +1078,13 @@
private void setDisabled2Flags(int state2) {
// Method only called on change of disable2 flags
- if (mNavigationBarView != null) {
- mNavigationBarView.getRotationButtonController().onDisable2FlagChanged(state2);
- }
+ mNavigationBarView.getRotationButtonController().onDisable2FlagChanged(state2);
}
// ----- Internal stuff -----
private void refreshLayout(int layoutDirection) {
- if (mNavigationBarView != null) {
- mNavigationBarView.setLayoutDirection(layoutDirection);
- }
+ mNavigationBarView.setLayoutDirection(layoutDirection);
}
private boolean shouldDisableNavbarGestures() {
@@ -1129,7 +1093,7 @@
}
private void repositionNavigationBar() {
- if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return;
+ if (!mNavigationBarView.isAttachedToWindow()) return;
prepareNavigationBarView();
@@ -1138,10 +1102,6 @@
}
private void updateScreenPinningGestures() {
- if (mNavigationBarView == null) {
- return;
- }
-
// Change the cancel pin gesture to home and back if recents button is invisible
boolean pinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive();
ButtonDispatcher backButton = mNavigationBarView.getBackButton();
@@ -1252,10 +1212,7 @@
AssistManager.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
mAssistManagerLazy.get().startAssist(args);
mStatusBarLazy.get().awakenDreams();
-
- if (mNavigationBarView != null) {
- mNavigationBarView.abortCurrentGesture();
- }
+ mNavigationBarView.abortCurrentGesture();
return true;
}
@@ -1405,9 +1362,6 @@
}
void updateAccessibilityServicesState(AccessibilityManager accessibilityManager) {
- if (mNavigationBarView == null) {
- return;
- }
boolean[] feedbackEnabled = new boolean[1];
int a11yFlags = getA11yButtonState(feedbackEnabled);
@@ -1593,7 +1547,7 @@
public void disableAnimationsDuringHide(long delay) {
mNavigationBarView.setLayoutTransitionsEnabled(false);
- mNavigationBarView.postDelayed(() -> mNavigationBarView.setLayoutTransitionsEnabled(true),
+ mHandler.postDelayed(mEnableLayoutTransitions,
delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
}
@@ -1608,10 +1562,7 @@
}
public NavigationBarTransitions getBarTransitions() {
- if (mNavigationBarView != null) {
- return mNavigationBarView.getBarTransitions();
- }
- return null;
+ return mNavigationBarView.getBarTransitions();
}
public void finishBarAnimations() {
@@ -1626,8 +1577,7 @@
}
private final Consumer<Integer> mRotationWatcher = rotation -> {
- if (mNavigationBarView != null
- && mNavigationBarView.needsReorient(rotation)) {
+ if (mNavigationBarView.needsReorient(rotation)) {
repositionNavigationBar();
}
};
@@ -1635,9 +1585,6 @@
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (mNavigationBarView == null) {
- return;
- }
String action = intent.getAction();
if (Intent.ACTION_SCREEN_OFF.equals(action)
|| Intent.ACTION_SCREEN_ON.equals(action)) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index ae9b598..8b5a537 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -123,8 +123,7 @@
// Tracks config changes that will actually recreate the nav bar
private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
- ActivityInfo.CONFIG_FONT_SCALE | ActivityInfo.CONFIG_LOCALE
- | ActivityInfo.CONFIG_SCREEN_LAYOUT
+ ActivityInfo.CONFIG_FONT_SCALE | ActivityInfo.CONFIG_SCREEN_LAYOUT
| ActivityInfo.CONFIG_UI_MODE);
@Inject
@@ -225,10 +224,7 @@
if (navBar == null) {
continue;
}
- NavigationBarView view = (NavigationBarView) navBar.getView();
- if (view != null) {
- view.updateStates();
- }
+ navBar.getView().updateStates();
}
});
}
@@ -366,13 +362,12 @@
mHandler,
mNavBarOverlayController,
mUiEventLogger);
+ mNavigationBars.put(displayId, navBar);
View navigationBarView = navBar.createView(savedState);
navigationBarView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
- mNavigationBars.put(displayId, navBar);
-
if (result != null) {
navBar.setImeWindowStatus(display.getDisplayId(), result.mImeToken,
result.mImeWindowVis, result.mImeBackDisposition,
@@ -448,7 +443,7 @@
*/
public @Nullable NavigationBarView getNavigationBarView(int displayId) {
NavigationBar navBar = mNavigationBars.get(displayId);
- return (navBar == null) ? null : (NavigationBarView) navBar.getView();
+ return (navBar == null) ? null : navBar.getView();
}
/** @return {@link NavigationBar} on the default display. */
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java
index 4d25079..0218016 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java
@@ -40,7 +40,6 @@
private final ArrayList<View> mViews = new ArrayList<>();
private final int mId;
- private final AssistManager mAssistManager;
private View.OnClickListener mClickListener;
private View.OnTouchListener mTouchListener;
@@ -73,7 +72,6 @@
public ButtonDispatcher(int id) {
mId = id;
- mAssistManager = Dependency.get(AssistManager.class);
}
public void clear() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 34c654c..1c5fa43 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -95,7 +95,7 @@
private boolean mLastKeyguardAndExpanded;
/**
* The last received state from the controller. This should not be used directly to check if
- * we're on keyguard but use {@link #isKeyguardShowing()} instead since that is more accurate
+ * we're on keyguard but use {@link #isKeyguardState()} instead since that is more accurate
* during state transitions which often call into us.
*/
private int mState;
@@ -326,7 +326,7 @@
|| mHeaderAnimating;
mQSPanelController.setExpanded(mQsExpanded);
mQSDetail.setExpanded(mQsExpanded);
- boolean keyguardShowing = isKeyguardShowing();
+ boolean keyguardShowing = isKeyguardState();
mHeader.setVisibility((mQsExpanded || !keyguardShowing || mHeaderAnimating
|| mShowCollapsedOnKeyguard)
? View.VISIBLE
@@ -344,7 +344,7 @@
!mQsDisabled && expandVisually ? View.VISIBLE : View.INVISIBLE);
}
- private boolean isKeyguardShowing() {
+ private boolean isKeyguardState() {
// We want the freshest state here since otherwise we'll have some weirdness if earlier
// listeners trigger updates
return mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
@@ -366,7 +366,7 @@
if (mQSAnimator != null) {
mQSAnimator.setShowCollapsedOnKeyguard(showCollapsed);
}
- if (!showCollapsed && isKeyguardShowing()) {
+ if (!showCollapsed && isKeyguardState()) {
setQsExpansion(mLastQSExpansion, 0);
}
}
@@ -457,7 +457,7 @@
mContainer.setExpansion(expansion);
final float translationScaleY = (mTranslateWhileExpanding
? 1 : QSAnimator.SHORT_PARALLAX_AMOUNT) * (expansion - 1);
- boolean onKeyguardAndExpanded = isKeyguardShowing() && !mShowCollapsedOnKeyguard;
+ boolean onKeyguardAndExpanded = isKeyguardState() && !mShowCollapsedOnKeyguard;
if (!mHeaderAnimating && !headerWillBeAnimating()) {
getView().setTranslationY(
onKeyguardAndExpanded
@@ -531,7 +531,6 @@
// The Media can be scrolled off screen by default, let's offset it
float expandedMediaPosition = absoluteBottomPosition - mQSPanelScrollView.getScrollY()
+ mQSPanelScrollView.getScrollRange();
- // The expanded media host should never move below the laid out position
pinToBottom(expandedMediaPosition, mQsMediaHost, true /* expanded */);
// The expanded media host should never move above the laid out position
pinToBottom(absoluteBottomPosition, mQqsMediaHost, false /* expanded */);
@@ -540,7 +539,8 @@
private void pinToBottom(float absoluteBottomPosition, MediaHost mediaHost, boolean expanded) {
View hostView = mediaHost.getHostView();
- if (mLastQSExpansion > 0) {
+ // on keyguard we cross-fade to expanded, so no need to pin it.
+ if (mLastQSExpansion > 0 && !isKeyguardState()) {
float targetPosition = absoluteBottomPosition - getTotalBottomMargin(hostView)
- hostView.getHeight();
float currentPosition = mediaHost.getCurrentBounds().top
@@ -573,7 +573,7 @@
private boolean headerWillBeAnimating() {
return mState == StatusBarState.KEYGUARD && mShowCollapsedOnKeyguard
- && !isKeyguardShowing();
+ && !isKeyguardState();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
index be7adbc..74d3425 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
@@ -430,12 +430,14 @@
} else {
state.icon = ResourceIcon.get(cb.mWifiSignalIconId);
}
- } else if (cb.mNoDefaultNetwork && cb.mNoNetworksAvailable) {
- state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
- state.secondaryLabel = r.getString(R.string.quick_settings_networks_unavailable);
- } else if (cb.mNoValidatedNetwork && !cb.mNoNetworksAvailable) {
- state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_available);
- state.secondaryLabel = r.getString(R.string.quick_settings_networks_available);
+ } else if (cb.mNoDefaultNetwork) {
+ if (cb.mNoNetworksAvailable) {
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
+ state.secondaryLabel = r.getString(R.string.quick_settings_networks_unavailable);
+ } else {
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_available);
+ state.secondaryLabel = r.getString(R.string.quick_settings_networks_available);
+ }
} else if (cb.mIsTransient) {
state.icon = ResourceIcon.get(
com.android.internal.R.drawable.ic_signal_wifi_transient_animation);
@@ -488,12 +490,14 @@
state.state = Tile.STATE_INACTIVE;
state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
state.secondaryLabel = r.getString(R.string.status_bar_airplane);
- } else if (cb.mNoDefaultNetwork && cb.mNoNetworksAvailable) {
- state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
- state.secondaryLabel = r.getString(R.string.quick_settings_networks_unavailable);
- } else if (cb.mNoValidatedNetwork && !cb.mNoNetworksAvailable) {
- state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_available);
- state.secondaryLabel = r.getString(R.string.quick_settings_networks_available);
+ } else if (cb.mNoDefaultNetwork) {
+ if (cb.mNoNetworksAvailable) {
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
+ state.secondaryLabel = r.getString(R.string.quick_settings_networks_unavailable);
+ } else {
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_available);
+ state.secondaryLabel = r.getString(R.string.quick_settings_networks_available);
+ }
} else {
state.icon = new SignalIcon(cb.mMobileSignalIconId);
state.secondaryLabel = appendMobileDataType(cb.mDataSubscriptionName,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
index e467925..64aec5e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
@@ -18,13 +18,14 @@
import static android.provider.Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT;
+import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE;
+
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.service.quickaccesswallet.GetWalletCardsError;
-import android.service.quickaccesswallet.GetWalletCardsRequest;
import android.service.quickaccesswallet.GetWalletCardsResponse;
import android.service.quickaccesswallet.QuickAccessWalletClient;
import android.service.quickaccesswallet.WalletCard;
@@ -51,6 +52,7 @@
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.android.systemui.wallet.ui.WalletActivity;
import java.util.List;
@@ -66,16 +68,15 @@
private final CharSequence mLabel = mContext.getString(R.string.wallet_title);
private final WalletCardRetriever mCardRetriever = new WalletCardRetriever();
- // TODO(b/180959290): Re-create the QAW Client when the default NFC payment app changes.
- private final QuickAccessWalletClient mQuickAccessWalletClient;
private final KeyguardStateController mKeyguardStateController;
private final PackageManager mPackageManager;
private final SecureSettings mSecureSettings;
private final Executor mExecutor;
+ private final QuickAccessWalletController mController;
private final FeatureFlags mFeatureFlags;
- @VisibleForTesting Drawable mCardViewDrawable;
private WalletCard mSelectedCard;
+ @VisibleForTesting Drawable mCardViewDrawable;
@Inject
public QuickAccessWalletTile(
@@ -87,15 +88,15 @@
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
- QuickAccessWalletClient quickAccessWalletClient,
KeyguardStateController keyguardStateController,
PackageManager packageManager,
SecureSettings secureSettings,
- @Background Executor executor,
+ @Main Executor executor,
+ QuickAccessWalletController quickAccessWalletController,
FeatureFlags featureFlags) {
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger);
- mQuickAccessWalletClient = quickAccessWalletClient;
+ mController = quickAccessWalletController;
mKeyguardStateController = keyguardStateController;
mPackageManager = packageManager;
mSecureSettings = secureSettings;
@@ -115,7 +116,11 @@
protected void handleSetListening(boolean listening) {
super.handleSetListening(listening);
if (listening) {
- queryWalletCards();
+ mController.setupWalletChangeObservers(mCardRetriever, DEFAULT_PAYMENT_APP_CHANGE);
+ if (!mController.getWalletClient().isWalletServiceAvailable()) {
+ mController.reCreateWalletClient();
+ }
+ mController.queryWalletCards(mCardRetriever);
}
}
@@ -139,12 +144,13 @@
mContext.startActivity(intent);
}
} else {
- if (mQuickAccessWalletClient.createWalletIntent() == null) {
+ if (mController.getWalletClient().createWalletIntent() == null) {
Log.w(TAG, "Could not get intent of the wallet app.");
return;
}
mActivityStarter.postStartActivityDismissingKeyguard(
- mQuickAccessWalletClient.createWalletIntent(), /* delay= */ 0,
+ mController.getWalletClient().createWalletIntent(),
+ /* delay= */ 0,
animationController);
}
});
@@ -152,30 +158,34 @@
@Override
protected void handleUpdateState(State state, Object arg) {
- CharSequence label = mQuickAccessWalletClient.getServiceLabel();
+ CharSequence label = mController.getWalletClient().getServiceLabel();
state.label = label == null ? mLabel : label;
state.contentDescription = state.label;
state.icon = ResourceIcon.get(R.drawable.ic_wallet_lockscreen);
boolean isDeviceLocked = !mKeyguardStateController.isUnlocked();
- if (mQuickAccessWalletClient.isWalletServiceAvailable()) {
+ if (mController.getWalletClient().isWalletServiceAvailable()) {
if (mSelectedCard != null) {
if (isDeviceLocked) {
state.state = Tile.STATE_INACTIVE;
state.secondaryLabel =
mContext.getString(R.string.wallet_secondary_label_device_locked);
+ state.sideViewCustomDrawable = null;
} else {
state.state = Tile.STATE_ACTIVE;
state.secondaryLabel = mSelectedCard.getContentDescription();
+ state.sideViewCustomDrawable = mCardViewDrawable;
}
} else {
state.state = Tile.STATE_INACTIVE;
state.secondaryLabel = mContext.getString(R.string.wallet_secondary_label_no_card);
+ state.sideViewCustomDrawable = null;
}
state.stateDescription = state.secondaryLabel;
} else {
state.state = Tile.STATE_UNAVAILABLE;
+ state.secondaryLabel = null;
+ state.sideViewCustomDrawable = null;
}
- state.sideViewCustomDrawable = isDeviceLocked ? null : mCardViewDrawable;
}
@Override
@@ -198,19 +208,14 @@
@Override
public CharSequence getTileLabel() {
- CharSequence label = mQuickAccessWalletClient.getServiceLabel();
+ CharSequence label = mController.getWalletClient().getServiceLabel();
return label == null ? mLabel : label;
}
- private void queryWalletCards() {
- int cardWidth =
- mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_width);
- int cardHeight =
- mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_height);
- int iconSizePx = mContext.getResources().getDimensionPixelSize(R.dimen.wallet_icon_size);
- GetWalletCardsRequest request =
- new GetWalletCardsRequest(cardWidth, cardHeight, iconSizePx, /* maxCards= */ 1);
- mQuickAccessWalletClient.getWalletCards(mExecutor, request, mCardRetriever);
+ @Override
+ protected void handleDestroy() {
+ super.handleDestroy();
+ mController.unregisterWalletChangeObservers(DEFAULT_PAYMENT_APP_CHANGE);
}
private class WalletCardRetriever implements
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 89cb5af..f4c15fb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -29,6 +29,7 @@
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SPLIT_SCREEN;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_STARTING_WINDOW;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS;
@@ -88,6 +89,7 @@
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
+import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -148,6 +150,7 @@
private final CommandQueue mCommandQueue;
private final ShellTransitions mShellTransitions;
private final Optional<StartingSurface> mStartingSurface;
+ private final SmartspaceTransitionController mSmartspaceTransitionController;
private Region mActiveNavBarRegion;
@@ -552,6 +555,9 @@
mStartingSurface.ifPresent((startingwindow) -> params.putBinder(
KEY_EXTRA_SHELL_STARTING_WINDOW,
startingwindow.createExternalInterface().asBinder()));
+ params.putBinder(
+ KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER,
+ mSmartspaceTransitionController.createExternalInterface().asBinder());
try {
Log.d(TAG_OPS + " b/182478748", "OverviewProxyService.onInitialize: curUser="
@@ -613,7 +619,8 @@
Optional<OneHanded> oneHandedOptional,
BroadcastDispatcher broadcastDispatcher,
ShellTransitions shellTransitions,
- Optional<StartingSurface> startingSurface) {
+ Optional<StartingSurface> startingSurface,
+ SmartspaceTransitionController smartspaceTransitionController) {
super(broadcastDispatcher);
mContext = context;
mPipOptional = pipOptional;
@@ -675,6 +682,7 @@
updateEnabledState();
startConnectionToCurrentUser();
mStartingSurface = startingSurface;
+ mSmartspaceTransitionController = smartspaceTransitionController;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index af4836d..facebee 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -861,11 +861,15 @@
class SwipeDismissHandler implements OnTouchListener {
// distance needed to register a dismissal
- private static final float DISMISS_DISTANCE_THRESHOLD_DP = 30;
+ private static final float DISMISS_DISTANCE_THRESHOLD_DP = 20;
private final GestureDetector mGestureDetector;
private float mStartX;
+ // Keeps track of the most recent direction (between the last two move events).
+ // -1 for left; +1 for right.
+ private int mDirectionX;
+ private float mPreviousX;
SwipeDismissHandler() {
GestureDetector.OnGestureListener gestureListener = new SwipeDismissGestureListener();
@@ -878,6 +882,7 @@
mCallbacks.onUserInteraction();
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
mStartX = event.getRawX();
+ mPreviousX = mStartX;
return true;
} else if (event.getActionMasked() == MotionEvent.ACTION_UP) {
if (isPastDismissThreshold()
@@ -906,16 +911,42 @@
public boolean onScroll(
MotionEvent ev1, MotionEvent ev2, float distanceX, float distanceY) {
mScreenshotStatic.setTranslationX(ev2.getRawX() - mStartX);
+ mDirectionX = (ev2.getRawX() < mPreviousX) ? -1 : 1;
+ mPreviousX = ev2.getRawX();
return true;
}
+
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
+ float velocityY) {
+ if (mScreenshotStatic.getTranslationX() * velocityX > 0
+ && (mDismissAnimation == null || !mDismissAnimation.isRunning())) {
+ animateDismissal(createSwipeDismissAnimation(velocityX / (float) 1000));
+ return true;
+ }
+ return false;
+ }
}
private boolean isPastDismissThreshold() {
- float distance = Math.abs(mScreenshotStatic.getTranslationX());
- return distance >= dpToPx(DISMISS_DISTANCE_THRESHOLD_DP);
+ float translationX = mScreenshotStatic.getTranslationX();
+ // Determines whether the absolute translation from the start is in the same direction
+ // as the current movement. For example, if the user moves most of the way to the right,
+ // but then starts dragging back left, we do not dismiss even though the absolute
+ // distance is greater than the threshold.
+ if (translationX * mDirectionX > 0) {
+ return Math.abs(translationX) >= dpToPx(DISMISS_DISTANCE_THRESHOLD_DP);
+ }
+ return false;
}
private ValueAnimator createSwipeDismissAnimation() {
+ return createSwipeDismissAnimation(1);
+ }
+
+ private ValueAnimator createSwipeDismissAnimation(float velocity) {
+ // velocity is measured in pixels per millisecond
+ velocity = Math.min(3, Math.max(1, velocity));
ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
float startX = mScreenshotStatic.getTranslationX();
// make sure the UI gets all the way off the screen in the direction of movement
@@ -924,13 +955,14 @@
float finalX = startX < 0
? -1 * mActionsContainerBackground.getRight()
: mDisplayMetrics.widthPixels;
+ float distance = Math.abs(finalX - startX);
anim.addUpdateListener(animation -> {
float translation = MathUtils.lerp(startX, finalX, animation.getAnimatedFraction());
mScreenshotStatic.setTranslationX(translation);
setAlpha(1 - animation.getAnimatedFraction());
});
- anim.setDuration(400);
+ anim.setDuration((long) (distance / Math.abs(velocity)));
return anim;
}
diff --git a/packages/SystemUI/src/com/android/systemui/shared/system/smartspace/SmartspaceTransitionController.kt b/packages/SystemUI/src/com/android/systemui/shared/system/smartspace/SmartspaceTransitionController.kt
new file mode 100644
index 0000000..89b3df0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shared/system/smartspace/SmartspaceTransitionController.kt
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.system.smartspace
+
+import android.graphics.Rect
+import android.view.View
+import com.android.systemui.shared.system.ActivityManagerWrapper
+import com.android.systemui.shared.system.QuickStepContract
+import kotlin.math.min
+
+/**
+ * Controller that keeps track of SmartSpace instances in remote processes (such as Launcher),
+ * allowing System UI to query or update their state during shared-element transitions.
+ */
+class SmartspaceTransitionController {
+
+ /**
+ * Implementation of [ISmartspaceTransitionController] that we provide to Launcher, allowing it
+ * to provide us with a callback to query and update the state of its Smartspace.
+ */
+ private val ISmartspaceTransitionController = object : ISmartspaceTransitionController.Stub() {
+ override fun setSmartspace(callback: ISmartspaceCallback?) {
+ this@SmartspaceTransitionController.launcherSmartspace = callback
+ updateLauncherSmartSpaceState()
+ }
+ }
+
+ /**
+ * Callback provided by Launcher to allow us to query and update the state of its SmartSpace.
+ */
+ public var launcherSmartspace: ISmartspaceCallback? = null
+
+ public var lockscreenSmartspace: View? = null
+
+ /**
+ * Cached state of the Launcher SmartSpace. Retrieving the state is an IPC, so we should avoid
+ * unnecessary
+ */
+ public var mLauncherSmartspaceState: SmartspaceState? = null
+
+ /**
+ * The bounds of our SmartSpace when the shared element transition began. We'll interpolate
+ * between this and [smartspaceDestinationBounds] as the dismiss amount changes.
+ */
+ private val smartspaceOriginBounds = Rect()
+
+ /** The bounds of the Launcher's SmartSpace, which is where we are animating our SmartSpace. */
+
+ private val smartspaceDestinationBounds = Rect()
+
+ fun createExternalInterface(): ISmartspaceTransitionController {
+ return ISmartspaceTransitionController
+ }
+
+ /**
+ * Updates [mLauncherSmartspaceState] and returns it. This will trigger a binder call, so use the
+ * cached [mLauncherSmartspaceState] if possible.
+ */
+ fun updateLauncherSmartSpaceState(): SmartspaceState? {
+ return launcherSmartspace?.smartspaceState.also {
+ mLauncherSmartspaceState = it
+ }
+ }
+
+ fun prepareForUnlockTransition() {
+ updateLauncherSmartSpaceState().also { state ->
+ if (state?.boundsOnScreen != null && lockscreenSmartspace != null) {
+ lockscreenSmartspace!!.getBoundsOnScreen(smartspaceOriginBounds)
+ with(smartspaceDestinationBounds) {
+ set(state.boundsOnScreen)
+ offset(-lockscreenSmartspace!!.paddingLeft,
+ -lockscreenSmartspace!!.paddingTop)
+ }
+ }
+ }
+ }
+
+ fun setProgressToDestinationBounds(progress: Float) {
+ if (!isSmartspaceTransitionPossible()) {
+ return
+ }
+
+ val progressClamped = min(1f, progress)
+
+ // Calculate the distance (relative to the origin) that we need to be for the current
+ // progress value.
+ val progressX =
+ (smartspaceDestinationBounds.left - smartspaceOriginBounds.left) * progressClamped
+ val progressY =
+ (smartspaceDestinationBounds.top - smartspaceOriginBounds.top) * progressClamped
+
+ val lockscreenSmartspaceCurrentBounds = Rect().also {
+ lockscreenSmartspace!!.getBoundsOnScreen(it)
+ }
+
+ // Figure out how far that is from our present location on the screen. This approach
+ // compensates for the fact that our parent container is also translating to animate out.
+ val dx = smartspaceOriginBounds.left + progressX -
+ lockscreenSmartspaceCurrentBounds.left
+ var dy = smartspaceOriginBounds.top + progressY -
+ lockscreenSmartspaceCurrentBounds.top
+
+ with(lockscreenSmartspace!!) {
+ translationX = translationX + dx
+ translationY = translationY + dy
+ }
+ }
+
+ /**
+ * Whether we're capable of performing the Smartspace shared element transition when we unlock.
+ * This is true if:
+ *
+ * - The Launcher registered a Smartspace with us, it's reporting non-empty bounds on screen.
+ * - Launcher is behind the keyguard, and the Smartspace is visible on the currently selected
+ * page.
+ */
+ public fun isSmartspaceTransitionPossible(): Boolean {
+ val smartSpaceNullOrBoundsEmpty = mLauncherSmartspaceState?.boundsOnScreen?.isEmpty ?: true
+ return isLauncherUnderneath() && !smartSpaceNullOrBoundsEmpty
+ }
+
+ companion object {
+ fun isLauncherUnderneath(): Boolean {
+ return ActivityManagerWrapper.getInstance()
+ .runningTask?.topActivity?.className?.equals(
+ QuickStepContract.LAUNCHER_ACTIVITY_CLASS_NAME) ?: false
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
index ac6d9e8..c7b6e67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
@@ -61,10 +61,6 @@
return mFlagReader.isEnabled(R.bool.flag_conversations);
}
- public boolean isToastStyleEnabled() {
- return mFlagReader.isEnabled(R.bool.flag_toast_style);
- }
-
public boolean isMonetEnabled() {
return mFlagReader.isEnabled(R.bool.flag_monet);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
index b33424c..acfd998 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
@@ -35,7 +35,6 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry.OnSensitivityChangedListener;
-import java.util.List;
/**
* The view in the statusBar that contains part of the heads-up information
@@ -55,10 +54,8 @@
private int[] mTmpPosition = new int[2];
private boolean mFirstLayout = true;
private int mMaxWidth;
- private View mRootView;
private int mSysWinInset;
private int mCutOutInset;
- private List<Rect> mCutOutBounds;
private Rect mIconDrawingRect = new Rect();
private Point mDisplaySize;
private Runnable mOnDrawingRectChangedListener;
@@ -197,19 +194,7 @@
int targetPadding = mAbsoluteStartPadding + mSysWinInset + mCutOutInset;
boolean isRtl = isLayoutRtl();
int start = isRtl ? (mDisplaySize.x - right) : left;
-
if (start != targetPadding) {
- if (mCutOutBounds != null) {
- for (Rect cutOutRect : mCutOutBounds) {
- int cutOutStart = (isRtl)
- ? (mDisplaySize.x - cutOutRect.right) : cutOutRect.left;
- if (start > cutOutStart) {
- start -= cutOutRect.width();
- break;
- }
- }
- }
-
int newPadding = targetPadding - start + getPaddingStart();
setPaddingRelative(newPadding, 0, mEndMargin, 0);
}
@@ -252,12 +237,6 @@
getDisplaySize();
- mCutOutBounds = null;
- if (displayCutout != null && displayCutout.getSafeInsetRight() == 0
- && displayCutout.getSafeInsetLeft() == 0) {
- mCutOutBounds = displayCutout.getBoundingRects();
- }
-
// For Double Cut Out mode, the System window navigation bar is at the right
// side of the left cut out. In this condition, mSysWinInset include the left cut
// out width so we set mCutOutInset to be 0. For RTL, the condition is the same.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
index b6357b8..045a197 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
@@ -36,6 +36,12 @@
*/
default void registerCallback(StatusBarWindowCallback callback) {}
+ /**
+ * Unregisters a {@link StatusBarWindowCallback previous registered with
+ * {@link #registerCallback(StatusBarWindowCallback)}}
+ */
+ default void unregisterCallback(StatusBarWindowCallback callback) {}
+
/** Notifies the registered {@link StatusBarWindowCallback} instances. */
default void notifyStateChangedCallbacks() {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 889dfde..9dc4ac9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -358,9 +358,13 @@
&& anv instanceof ExpandableNotificationRow
&& ((ExpandableNotificationRow) anv).isHeadsUp();
+ final boolean isHunGoingToShade = mAmbientState.isShadeExpanded()
+ && anv == mAmbientState.getTrackedHeadsUpRow();
+
final boolean shouldUpdateCornerRoundness = viewStart < shelfStart
&& !mHostLayoutController.isViewAffectedBySwipe(anv)
&& !isUnlockedHeadsUp
+ && !isHunGoingToShade
&& !mAmbientState.isPulsing()
&& !mAmbientState.isDozing();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
index 91415f27..05afc57f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
@@ -83,6 +83,7 @@
var rippleView: ChargingRippleView = ChargingRippleView(context, attrs = null)
init {
+ pluggedIn = batteryController.isPluggedIn
val batteryStateChangeCallback = object : BatteryController.BatteryStateChangeCallback {
override fun onBatteryLevelChanged(
level: Int,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
index 655ed41..33aa7c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
@@ -26,14 +26,18 @@
import android.provider.DeviceConfig
import android.util.Log
import android.view.View
+import com.android.systemui.Dumpable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.phone.StatusBarWindowController
import com.android.systemui.statusbar.policy.CallbackController
import com.android.systemui.util.Assert
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.time.SystemClock
+import java.io.FileDescriptor
+import java.io.PrintWriter
import javax.inject.Inject
@@ -59,9 +63,10 @@
private val coordinator: SystemEventCoordinator,
private val chipAnimationController: SystemEventChipAnimationController,
private val statusBarWindowController: StatusBarWindowController,
+ private val dumpManager: DumpManager,
private val systemClock: SystemClock,
@Main private val executor: DelayableExecutor
-) : CallbackController<SystemStatusAnimationCallback> {
+) : CallbackController<SystemStatusAnimationCallback>, Dumpable {
companion object {
private const val PROPERTY_ENABLE_IMMERSIVE_INDICATOR = "enable_immersive_indicator"
@@ -71,10 +76,6 @@
PROPERTY_ENABLE_IMMERSIVE_INDICATOR, true)
}
- /** True from the time a scheduled event starts until it's animation finishes */
- var isActive = false
- private set
-
@SystemAnimationState var animationState: Int = IDLE
private set
@@ -88,6 +89,7 @@
init {
coordinator.attachScheduler(this)
+ dumpManager.registerDumpable(TAG, this)
}
fun onStatusEvent(event: StatusEvent) {
@@ -293,6 +295,20 @@
anim -> chipAnimationController.onChipAnimationUpdate(anim, animationState)
}
+ override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
+ pw.println("Scheduled event: $scheduledEvent")
+ pw.println("Has persistent privacy dot: $hasPersistentDot")
+ pw.println("Animation state: $animationState")
+ pw.println("Listeners:")
+ if (listeners.isEmpty()) {
+ pw.println("(none)")
+ } else {
+ listeners.forEach {
+ pw.println(" $it")
+ }
+ }
+ }
+
inner class ChipAnimatorAdapter(
@SystemAnimationState val endState: Int,
val viewCreator: (context: Context) -> View
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 21d8164..94edbd0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -5145,8 +5145,8 @@
}
/**
- * Sets the extra top inset for the full shade transition. This is needed to compensate for
- * media transitioning to quick settings
+ * Sets the extra top inset for the full shade transition. This moves notifications down
+ * during the drag down.
*/
public void setExtraTopInsetForFullShadeTransition(float inset) {
mExtraTopInsetForFullShadeTransition = inset;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index d23a309..4432f54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -185,8 +185,17 @@
private ColorExtractor.OnColorsChangedListener mOnColorsChangedListener;
+ /**
+ * The total distance in pixels that the full shade transition takes to transition entirely to
+ * the full shade.
+ */
private int mTotalDistanceForFullShadeTransition;
- private int mTotalExtraMediaInsetFullShadeTransition;
+
+ /**
+ * The amount of movement the notifications do when transitioning to the full shade before
+ * reaching the overstrech
+ */
+ private int mNotificationDragDownMovement;
@VisibleForTesting
final View.OnAttachStateChangeListener mOnAttachStateChangeListener =
@@ -255,8 +264,8 @@
};
private void updateResources() {
- mTotalExtraMediaInsetFullShadeTransition = mResources.getDimensionPixelSize(
- R.dimen.lockscreen_shade_transition_extra_media_inset);
+ mNotificationDragDownMovement = mResources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_notification_movement);
mTotalDistanceForFullShadeTransition = mResources.getDimensionPixelSize(
R.dimen.lockscreen_shade_qs_transition_distance);
}
@@ -1410,15 +1419,13 @@
* shade. 0.0f means we're not transitioning yet.
*/
public void setTransitionToFullShadeAmount(float amount) {
- float extraTopInset;
- MediaHeaderView view = mKeyguardMediaController.getSinglePaneContainer();
- if (view == null || view.getHeight() == 0
- || mStatusBarStateController.getState() != KEYGUARD) {
- extraTopInset = 0;
- } else {
- extraTopInset = MathUtils.saturate(amount / mTotalDistanceForFullShadeTransition);
- extraTopInset = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(extraTopInset);
- extraTopInset = extraTopInset * mTotalExtraMediaInsetFullShadeTransition;
+ float extraTopInset = 0.0f;
+ if (mStatusBarStateController.getState() == KEYGUARD) {
+ float overallProgress = MathUtils.saturate(amount / mView.getHeight());
+ float transitionProgress = Interpolators.getOvershootInterpolation(overallProgress,
+ 0.6f,
+ (float) mTotalDistanceForFullShadeTransition / (float) mView.getHeight());
+ extraTopInset = transitionProgress * mNotificationDragDownMovement;
}
mView.setExtraTopInsetForFullShadeTransition(extraTopInset);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index d9cbfda..86465b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -380,11 +380,15 @@
ExpandableViewState viewState = view.getViewState();
viewState.location = ExpandableViewState.LOCATION_UNKNOWN;
- if (ambientState.isExpansionChanging() && !ambientState.isOnKeyguard()) {
- viewState.alpha = Interpolators.getNotificationScrimAlpha(
- ambientState.getExpansionFraction(), true /* notification */);
- } else {
- viewState.alpha = 1f - ambientState.getHideAmount();
+ final boolean isHunGoingToShade = ambientState.isShadeExpanded()
+ && view == ambientState.getTrackedHeadsUpRow();
+ if (!isHunGoingToShade) {
+ if (ambientState.isExpansionChanging() && !ambientState.isOnKeyguard()) {
+ viewState.alpha = Interpolators.getNotificationScrimAlpha(
+ ambientState.getExpansionFraction(), true /* notification */);
+ } else {
+ viewState.alpha = 1f - ambientState.getHideAmount();
+ }
}
if (view.mustStayOnScreen() && viewState.yTranslation >= 0) {
@@ -414,13 +418,15 @@
}
if (view instanceof FooterView) {
+ final boolean shadeClosed = !ambientState.isShadeExpanded();
final boolean isShelfShowing = algorithmState.firstViewInShelf != null;
final float footerEnd = algorithmState.mCurrentExpandedYPosition
+ view.getIntrinsicHeight();
final boolean noSpaceForFooter = footerEnd > ambientState.getStackEndHeight();
- viewState.hidden = isShelfShowing || noSpaceForFooter;
+ viewState.hidden = shadeClosed || isShelfShowing || noSpaceForFooter;
+
} else if (view != ambientState.getTrackedHeadsUpRow()) {
if (ambientState.isExpansionChanging()) {
// Show all views. Views below the shelf will later be clipped (essentially hidden)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 7f919b5..4d8e7de3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -24,6 +24,8 @@
import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_UNLOCK;
import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_BUTTON;
import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_UNLOCK;
+import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE;
+import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE;
import android.app.ActivityManager;
import android.app.ActivityOptions;
@@ -39,7 +41,6 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
-import android.database.ContentObserver;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
@@ -49,13 +50,10 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.MediaStore;
-import android.provider.Settings;
import android.service.media.CameraPrewarmService;
import android.service.quickaccesswallet.GetWalletCardsError;
-import android.service.quickaccesswallet.GetWalletCardsRequest;
import android.service.quickaccesswallet.GetWalletCardsResponse;
import android.service.quickaccesswallet.QuickAccessWalletClient;
-import android.service.quickaccesswallet.QuickAccessWalletClientImpl;
import android.telecom.TelecomManager;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -71,7 +69,6 @@
import android.widget.TextView;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.LockPatternUtils;
@@ -97,11 +94,9 @@
import com.android.systemui.statusbar.policy.PreviewInflater;
import com.android.systemui.tuner.LockscreenFragment.LockButtonFactory;
import com.android.systemui.tuner.TunerService;
-import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.android.systemui.wallet.ui.WalletActivity;
-import java.util.concurrent.Executor;
-
/**
* Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
* text.
@@ -137,10 +132,9 @@
private KeyguardAffordanceView mLeftAffordanceView;
private ImageView mWalletButton;
- private boolean mWalletEnabled = false;
private boolean mHasCard = false;
private WalletCardRetriever mCardRetriever = new WalletCardRetriever();
- private QuickAccessWalletClient mQuickAccessWalletClient;
+ private QuickAccessWalletController mQuickAccessWalletController;
private ViewGroup mIndicationArea;
private TextView mIndicationText;
@@ -159,7 +153,6 @@
private StatusBar mStatusBar;
private KeyguardAffordanceHelper mAffordanceHelper;
private FalsingManager mFalsingManager;
- @Nullable private Executor mUiExecutor;
private boolean mUserSetupComplete;
private boolean mPrewarmBound;
private Messenger mPrewarmMessenger;
@@ -193,8 +186,6 @@
private int mBurnInYOffset;
private ActivityIntentHelper mActivityIntentHelper;
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private ContentObserver mWalletPreferenceObserver;
- private SecureSettings mSecureSettings;
public KeyguardBottomAreaView(Context context) {
this(context, null);
@@ -332,8 +323,9 @@
getContext().unregisterReceiver(mDevicePolicyReceiver);
mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
- if (mWalletPreferenceObserver != null) {
- mSecureSettings.unregisterContentObserver(mWalletPreferenceObserver);
+ if (mQuickAccessWalletController != null) {
+ mQuickAccessWalletController.unregisterWalletChangeObservers(
+ WALLET_PREFERENCE_CHANGE, DEFAULT_PAYMENT_APP_CHANGE);
}
}
@@ -456,7 +448,10 @@
}
private void updateWalletVisibility() {
- if (mDozing || !mWalletEnabled || !mHasCard) {
+ if (mDozing
+ || mQuickAccessWalletController == null
+ || !mQuickAccessWalletController.isWalletEnabled()
+ || !mHasCard) {
mWalletButton.setVisibility(GONE);
mIndicationArea.setPadding(0, 0, 0, 0);
} else {
@@ -690,7 +685,9 @@
@Override
public void onKeyguardShowingChanged() {
if (mKeyguardStateController.isShowing()) {
- queryWalletCards();
+ if (mQuickAccessWalletController != null) {
+ mQuickAccessWalletController.queryWalletCards(mCardRetriever);
+ }
}
}
@@ -935,50 +932,17 @@
/**
* Initialize the wallet feature, only enabling if the feature is enabled within the platform.
*/
- public void initWallet(QuickAccessWalletClient client, Executor uiExecutor,
- SecureSettings secureSettings) {
- mQuickAccessWalletClient = client;
- mSecureSettings = secureSettings;
- setupWalletPreferenceObserver();
- updateWalletPreference();
-
- mUiExecutor = uiExecutor;
- queryWalletCards();
+ public void initWallet(
+ QuickAccessWalletController controller) {
+ mQuickAccessWalletController = controller;
+ mQuickAccessWalletController.setupWalletChangeObservers(
+ mCardRetriever, WALLET_PREFERENCE_CHANGE, DEFAULT_PAYMENT_APP_CHANGE);
+ mQuickAccessWalletController.updateWalletPreference();
+ mQuickAccessWalletController.queryWalletCards(mCardRetriever);
updateWalletVisibility();
}
- private void setupWalletPreferenceObserver() {
- if (mWalletPreferenceObserver == null) {
- mWalletPreferenceObserver = new ContentObserver(null /* handler */) {
- @Override
- public void onChange(boolean selfChange) {
- mUiExecutor.execute(() -> updateWalletPreference());
- }
- };
-
- mSecureSettings.registerContentObserver(
- Settings.Secure.getUriFor(QuickAccessWalletClientImpl.SETTING_KEY),
- false /* notifyForDescendants */,
- mWalletPreferenceObserver);
- }
- }
-
- private void updateWalletPreference() {
- mWalletEnabled = mQuickAccessWalletClient.isWalletFeatureAvailable()
- && mQuickAccessWalletClient.isWalletFeatureAvailableWhenDeviceLocked();
- }
-
- private void queryWalletCards() {
- if (!mWalletEnabled || mUiExecutor == null) {
- return;
- }
- GetWalletCardsRequest request =
- new GetWalletCardsRequest(1 /* cardWidth */, 1 /* cardHeight */,
- 1 /* iconSizePx */, 1 /* maxCards */);
- mQuickAccessWalletClient.getWalletCards(mUiExecutor, request, mCardRetriever);
- }
-
private void onWalletClick(View v) {
// More coming here; need to inform the user about how to proceed
if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
@@ -991,12 +955,13 @@
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
} else {
- if (mQuickAccessWalletClient.createWalletIntent() == null) {
+ if (mQuickAccessWalletController.getWalletClient().createWalletIntent() == null) {
Log.w(TAG, "Could not get intent of the wallet app.");
return;
}
mActivityStarter.postStartActivityDismissingKeyguard(
- mQuickAccessWalletClient.createWalletIntent(), /* delay= */ 0);
+ mQuickAccessWalletController.getWalletClient().createWalletIntent(),
+ /* delay= */ 0);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index f4710f4..7c2723d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -325,7 +325,9 @@
*/
private float getClockAlpha(int y) {
float alphaKeyguard = Math.max(0, y / Math.max(1f, getClockY(1f, mDarkAmount)));
- alphaKeyguard *= (1f - mQsExpansion);
+ float qsAlphaFactor = MathUtils.saturate(mQsExpansion / 0.3f);
+ qsAlphaFactor = 1f - qsAlphaFactor;
+ alphaKeyguard *= qsAlphaFactor;
alphaKeyguard = Interpolators.ACCELERATE.getInterpolation(alphaKeyguard);
return MathUtils.lerp(alphaKeyguard, 1f, mDarkAmount);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
index d84bb90..68e2070 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
@@ -142,7 +142,6 @@
Animator yTranslate =
ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, 0, -getYTranslationPixels());
yTranslate.setDuration(getFadeOutDuration());
- fadeOut.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
animatorSet.playTogether(fadeOut, yTranslate);
return animatorSet;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 0c4bec2c..eef2420 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -116,6 +116,12 @@
// right and left padding applied to this view to account for cutouts and rounded corners
private Pair<Integer, Integer> mPadding = new Pair(0, 0);
+ /**
+ * The clipping on the top
+ */
+ private int mTopClipping;
+ private final Rect mClipRect = new Rect(0, 0, 0, 0);
+
public KeyguardStatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
mUserManager = UserManager.get(getContext());
@@ -549,4 +555,25 @@
public void onSystemChromeAnimationUpdate(ValueAnimator anim) {
mSystemIconsContainer.setAlpha((float) anim.getAnimatedValue());
}
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ updateClipping();
+ }
+
+ /**
+ * Set the clipping on the top of the view.
+ */
+ public void setTopClipping(int topClipping) {
+ if (topClipping != mTopClipping) {
+ mTopClipping = topClipping;
+ updateClipping();
+ }
+ }
+
+ private void updateClipping() {
+ mClipRect.set(0, mTopClipping, getWidth(), getHeight());
+ setClipBounds(mClipRect);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 0f3af09..d9ba494 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -24,6 +24,8 @@
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
+import com.android.systemui.R;
+
public class NotificationPanelView extends PanelView {
private static final boolean DEBUG = false;
@@ -92,6 +94,10 @@
mRtlChangeListener = listener;
}
+ public TapAgainView getTapAgainView() {
+ return findViewById(R.id.shade_falsing_tap_again);
+ }
+
interface RtlChangeListener {
void onRtlPropertielsChanged(int layoutDirection);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 1263b10..efcde46 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -54,7 +54,6 @@
import android.os.SystemClock;
import android.os.UserManager;
import android.os.VibrationEffect;
-import android.service.quickaccesswallet.QuickAccessWalletClient;
import android.util.Log;
import android.util.MathUtils;
import android.view.DisplayCutout;
@@ -97,8 +96,8 @@
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeLog;
-import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
+import com.android.systemui.fragments.FragmentService;
import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.MediaHierarchyManager;
@@ -153,6 +152,7 @@
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.util.Utils;
import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.android.wm.shell.animation.FlingAnimationUtils;
import java.io.FileDescriptor;
@@ -306,14 +306,17 @@
private final KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory;
private final KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory;
private final QSDetailDisplayer mQSDetailDisplayer;
+ private final FragmentService mFragmentService;
private final FeatureFlags mFeatureFlags;
private final ScrimController mScrimController;
private final PrivacyDotViewController mPrivacyDotViewController;
+ private final QuickAccessWalletController mQuickAccessWalletController;
// Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow card.
// If there are exactly 1 + mMaxKeyguardNotifications, then still shows all notifications
private final int mMaxKeyguardNotifications;
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+ private final TapAgainViewController mTapAgainViewController;
private boolean mShouldUseSplitNotificationShade;
// Current max allowed keyguard notifications determined by measuring the panel
private int mMaxAllowedKeyguardNotifications;
@@ -508,6 +511,13 @@
private float mSectionPadding;
/**
+ * The padding between the start of notifications and the qs boundary on the lockscreen.
+ * On lockscreen, notifications aren't inset this extra amount, but we still want the
+ * qs boundary to be padded.
+ */
+ private int mLockscreenNotificationQSPadding;
+
+ /**
* The amount of progress we are currently in if we're transitioning to the full shade.
* 0.0f means we're not transitioning yet, while 1 means we're all the way in the full
* shade. This value can also go beyond 1.1 when we're overshooting!
@@ -529,7 +539,7 @@
/**
* The maximum overshoot allowed for the top padding for the full shade transition
*/
- private int mMaxOverscrollAmountForDragDown;
+ private int mMaxOverscrollAmountForPulse;
/**
* Should we animate the next bounds update
@@ -573,8 +583,8 @@
private int mScrimCornerRadius;
private int mScreenCornerRadius;
private int mNotificationScrimPadding;
+ private boolean mQSAnimatingHiddenFromCollapsed;
- private final QuickAccessWalletClient mQuickAccessWalletClient;
private final Executor mUiExecutor;
private final SecureSettings mSecureSettings;
@@ -604,7 +614,12 @@
private final FalsingTapListener mFalsingTapListener = new FalsingTapListener() {
@Override
public void onDoubleTapRequired() {
- showTransientIndication(R.string.notification_tap_again);
+ if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED) {
+ mTapAgainViewController.show();
+ } else {
+ mKeyguardIndicationController.showTransientIndication(
+ R.string.notification_tap_again);
+ }
mVibratorHelper.vibrate(VibrationEffect.EFFECT_STRENGTH_MEDIUM);
}
};
@@ -650,9 +665,11 @@
AmbientState ambientState,
LockIconViewController lockIconViewController,
FeatureFlags featureFlags,
- QuickAccessWalletClient quickAccessWalletClient,
KeyguardMediaController keyguardMediaController,
PrivacyDotViewController privacyDotViewController,
+ TapAgainViewController tapAgainViewController,
+ FragmentService fragmentService,
+ QuickAccessWalletController quickAccessWalletController,
@Main Executor uiExecutor,
SecureSettings secureSettings) {
super(view, falsingManager, dozeLog, keyguardStateController,
@@ -663,6 +680,7 @@
mVibratorHelper = vibratorHelper;
mKeyguardMediaController = keyguardMediaController;
mPrivacyDotViewController = privacyDotViewController;
+ mQuickAccessWalletController = quickAccessWalletController;
mMetricsLogger = metricsLogger;
mActivityManager = activityManager;
mConfigurationController = configurationController;
@@ -679,6 +697,7 @@
mKeyguardQsUserSwitchComponentFactory = keyguardQsUserSwitchComponentFactory;
mKeyguardUserSwitcherComponentFactory = keyguardUserSwitcherComponentFactory;
mQSDetailDisplayer = qsDetailDisplayer;
+ mFragmentService = fragmentService;
mKeyguardUserSwitcherEnabled = mResources.getBoolean(
com.android.internal.R.bool.config_keyguardUserSwitcher);
mKeyguardQsUserSwitchEnabled =
@@ -704,7 +723,7 @@
mScrimController.setClipsQsScrim(!mShouldUseSplitNotificationShade);
mUserManager = userManager;
mMediaDataManager = mediaDataManager;
- mQuickAccessWalletClient = quickAccessWalletClient;
+ mTapAgainViewController = tapAgainViewController;
mUiExecutor = uiExecutor;
mSecureSettings = secureSettings;
pulseExpansionHandler.setPulseExpandAbortListener(() -> {
@@ -812,7 +831,7 @@
amount -> {
float progress = amount / mView.getHeight();
float overstretch = Interpolators.getOvershootInterpolation(progress,
- (float) mMaxOverscrollAmountForDragDown / mView.getHeight(),
+ (float) mMaxOverscrollAmountForPulse / mView.getHeight(),
0.2f);
setOverStrechAmount(overstretch);
});
@@ -843,6 +862,8 @@
if (mShouldUseSplitNotificationShade) {
updateResources();
}
+
+ mTapAgainViewController.init();
}
@Override
@@ -873,14 +894,16 @@
R.dimen.heads_up_status_bar_padding);
mDistanceForQSFullShadeTransition = mResources.getDimensionPixelSize(
R.dimen.lockscreen_shade_qs_transition_distance);
- mMaxOverscrollAmountForDragDown = mResources.getDimensionPixelSize(
- R.dimen.lockscreen_shade_max_top_overshoot);
+ mMaxOverscrollAmountForPulse = mResources.getDimensionPixelSize(
+ R.dimen.pulse_expansion_max_top_overshoot);
mScrimCornerRadius = mResources.getDimensionPixelSize(
R.dimen.notification_scrim_corner_radius);
mScreenCornerRadius = mResources.getDimensionPixelSize(
com.android.internal.R.dimen.rounded_corner_radius);
mNotificationScrimPadding = mResources.getDimensionPixelSize(
R.dimen.notification_side_paddings);
+ mLockscreenNotificationQSPadding = mResources.getDimensionPixelSize(
+ R.dimen.notification_side_paddings);
}
private void updateViewControllers(KeyguardStatusView keyguardStatusView,
@@ -1100,7 +1123,7 @@
mKeyguardBottomArea.setFalsingManager(mFalsingManager);
if (mFeatureFlags.isQuickAccessWalletEnabled()) {
- mKeyguardBottomArea.initWallet(mQuickAccessWalletClient, mUiExecutor, mSecureSettings);
+ mKeyguardBottomArea.initWallet(mQuickAccessWalletController);
}
}
@@ -1421,7 +1444,7 @@
}
mStatusBar.getGutsManager().closeAndSaveGuts(true /* leavebehind */, true /* force */,
true /* controls */, -1 /* x */, -1 /* y */, true /* resetMenu */);
- if (animate) {
+ if (animate && !isFullyCollapsed()) {
animateCloseQs(true /* animateAway */);
} else {
closeQs();
@@ -1705,6 +1728,11 @@
}
private float computeQsExpansionFraction() {
+ if (mQSAnimatingHiddenFromCollapsed) {
+ // When hiding QS from collapsed state, the expansion can sometimes temporarily
+ // be larger than 0 because of the timing, leading to flickers.
+ return 0.0f;
+ }
return Math.min(
1f, (mQsExpansionHeight - mQsMinExpansionHeight) / (mQsMaxExpansionHeight
- mQsMinExpansionHeight));
@@ -2238,19 +2266,24 @@
boolean visible) {
// Fancy clipping for quick settings
int radius = mScrimCornerRadius;
+ int statusBarClipTop = 0;
+ boolean clipStatusView = false;
if (!mShouldUseSplitNotificationShade) {
// The padding on this area is large enough that we can use a cheaper clipping strategy
mKeyguardStatusAreaClipBounds.set(left, top, right, bottom);
- mKeyguardStatusViewController.setClipBounds(visible
- ? mKeyguardStatusAreaClipBounds : null);
+ clipStatusView = visible;
radius = (int) MathUtils.lerp(mScreenCornerRadius, mScrimCornerRadius,
Math.min(top / (float) mScrimCornerRadius, 1f));
+ statusBarClipTop = top - mKeyguardStatusBar.getTop();
}
if (mQs != null) {
mQs.setFancyClipping(top, bottom, radius, visible);
}
+ mKeyguardStatusViewController.setClipBounds(
+ clipStatusView ? mKeyguardStatusAreaClipBounds : null);
mScrimController.setNotificationsBounds(left, top, right, bottom);
mScrimController.setScrimCornerRadius(radius);
+ mKeyguardStatusBar.setTopClipping(statusBarClipTop);
}
private float getQSEdgePosition() {
@@ -2367,7 +2400,6 @@
public void setTransitionToFullShadeAmount(float pxAmount, boolean animate, long delay) {
mAnimateNextNotificationBounds = animate && !mShouldUseSplitNotificationShade;
mNotificationBoundsAnimationDelay = delay;
- float progress = MathUtils.saturate(pxAmount / mView.getHeight());
float endPosition = 0;
if (pxAmount > 0.0f) {
@@ -2375,29 +2407,28 @@
&& !mMediaDataManager.hasActiveMedia()) {
// No notifications are visible, let's animate to the height of qs instead
if (mQs != null) {
- // Let's interpolate to the header height
- endPosition = mQs.getHeader().getHeight();
+ // Let's interpolate to the header height instead of the top padding,
+ // because the toppadding is way too low because of the large clock.
+ // we still want to take into account the edgePosition though as that nicely
+ // overshoots in the stackscroller
+ endPosition = getQSEdgePosition()
+ - mNotificationStackScrollLayoutController.getTopPadding()
+ + mQs.getHeader().getHeight();
}
} else {
// Interpolating to the new bottom edge position!
- endPosition = getQSEdgePosition() - mOverStretchAmount;
-
- // If we have media, we need to put the boundary below it, as the media header
- // still uses the space during the transition.
- endPosition +=
- mNotificationStackScrollLayoutController.getFullShadeTransitionInset();
+ endPosition = getQSEdgePosition()
+ + mNotificationStackScrollLayoutController.getFullShadeTransitionInset();
+ if (isOnKeyguard()) {
+ endPosition -= mLockscreenNotificationQSPadding;
+ }
}
}
// Calculate the overshoot amount such that we're reaching the target after our desired
// distance, but only reach it fully once we drag a full shade length.
- float transitionProgress = 0;
- if (endPosition != 0 && progress != 0) {
- transitionProgress = Interpolators.getOvershootInterpolation(progress,
- mMaxOverscrollAmountForDragDown / endPosition,
- (float) mDistanceForQSFullShadeTransition / (float) mView.getHeight());
- }
- mTransitioningToFullShadeProgress = transitionProgress;
+ mTransitioningToFullShadeProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
+ MathUtils.saturate(pxAmount / mDistanceForQSFullShadeTransition));
int position = (int) MathUtils.lerp((float) 0, endPosition,
mTransitioningToFullShadeProgress);
@@ -2405,8 +2436,6 @@
// we want at least 1 pixel otherwise the panel won't be clipped
position = Math.max(1, position);
}
- float overStretchAmount = Math.max(position - endPosition, 0.0f);
- setOverStrechAmount(overStretchAmount);
mTransitionToFullShadeQSPosition = position;
updateQsExpansion();
}
@@ -2509,6 +2538,7 @@
@Override
public void onAnimationEnd(Animator animation) {
+ mQSAnimatingHiddenFromCollapsed = false;
mAnimatingQS = false;
notifyExpandingFinished();
mNotificationStackScrollLayoutController.resetCheckSnoozeLeavebehind();
@@ -2525,6 +2555,7 @@
animator.start();
mQsExpansionAnimator = animator;
mQsAnimatorExpand = expanding;
+ mQSAnimatingHiddenFromCollapsed = computeQsExpansionFraction() == 0.0f && target == 0;
}
/**
@@ -3675,10 +3706,6 @@
updateMaxDisplayedNotifications(true);
}
- public void showTransientIndication(int id) {
- mKeyguardIndicationController.showTransientIndication(id);
- }
-
public void setAlpha(float alpha) {
mView.setAlpha(alpha);
}
@@ -4264,7 +4291,8 @@
private class OnAttachStateChangeListener implements View.OnAttachStateChangeListener {
@Override
public void onViewAttachedToWindow(View v) {
- FragmentHostManager.get(mView).addTagListener(QS.TAG, mFragmentListener);
+ mFragmentService.getFragmentHostManager(mView)
+ .addTagListener(QS.TAG, mFragmentListener);
mStatusBarStateController.addCallback(mStatusBarStateListener);
mConfigurationController.addCallback(mConfigurationListener);
mUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
@@ -4278,7 +4306,8 @@
@Override
public void onViewDetachedFromWindow(View v) {
- FragmentHostManager.get(mView).removeTagListener(QS.TAG, mFragmentListener);
+ mFragmentService.getFragmentHostManager(mView)
+ .removeTagListener(QS.TAG, mFragmentListener);
mStatusBarStateController.removeCallback(mStatusBarStateListener);
mConfigurationController.removeCallback(mConfigurationListener);
mUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
index ae018ba..52f9aca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -152,6 +152,16 @@
mCallbacks.add(new WeakReference<StatusBarWindowCallback>(callback));
}
+ @Override
+ public void unregisterCallback(StatusBarWindowCallback callback) {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ if (mCallbacks.get(i).get() == callback) {
+ mCallbacks.remove(i);
+ return;
+ }
+ }
+ }
+
/**
* Register a listener to monitor scrims visibility
* @param listener A listener to monitor scrims visibility
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index ba2340e..c27497e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -464,6 +464,7 @@
protected final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private final BrightnessSlider.Factory mBrightnessSliderFactory;
private final FeatureFlags mFeatureFlags;
+ private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private final List<ExpansionChangedListener> mExpansionChangedListeners;
@@ -885,6 +886,8 @@
mAnimationScheduler = animationScheduler;
mStatusBarLocationPublisher = locationPublisher;
mFeatureFlags = featureFlags;
+ mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
+
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
lockscreenShadeTransitionController.setStatusbar(this);
@@ -1369,7 +1372,8 @@
// are already animating the keyguard dismiss (since we will need to either finish or cancel
// the animation).
if (trackingTouch
- || mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()) {
+ || mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()
+ || mKeyguardUnlockAnimationController.isUnlockingWithSmartSpaceTransition()) {
mKeyguardStateController.notifyKeyguardDismissAmountChanged(
1f - expansion, trackingTouch);
}
@@ -4386,6 +4390,7 @@
} else {
mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
}
+ updateLightRevealScrimVisibility();
Trace.endSection();
}
@@ -4818,6 +4823,11 @@
return;
}
+ if (mDozeServiceHost.isPulsing()) {
+ mLightRevealScrim.setVisibility(View.GONE);
+ return;
+ }
+
if (mFeatureFlags.useNewLockscreenAnimations()
&& (mDozeParameters.getAlwaysOn() || mDozeParameters.isQuickPickupEnabled())) {
mLightRevealScrim.setVisibility(View.VISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt
index 8befe80..edcf261 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt
@@ -23,6 +23,8 @@
import android.view.DisplayCutout
import android.view.View.LAYOUT_DIRECTION_RTL
import android.view.WindowManager
+import android.view.WindowMetrics
+import androidx.annotation.VisibleForTesting
import com.android.systemui.Dumpable
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
@@ -118,17 +120,8 @@
val chipWidth = rotatedResources.getDimensionPixelSize(
R.dimen.ongoing_appops_chip_max_width)
- return if (context.resources.configuration.layoutDirection == LAYOUT_DIRECTION_RTL) {
- Rect(insets.left - dotWidth,
- insets.top,
- insets.left + chipWidth,
- insets.bottom)
- } else {
- Rect(insets.right - chipWidth,
- insets.top,
- insets.right + dotWidth,
- insets.bottom)
- }
+ val isRtl = context.resources.configuration.layoutDirection == LAYOUT_DIRECTION_RTL
+ return getPrivacyChipBoundingRectForInsets(insets, dotWidth, chipWidth, isRtl)
}
/**
@@ -139,8 +132,7 @@
var insets = insetsByCorner[rotation]
if (insets == null) {
val rotatedResources = RotationUtils.getResourcesForRotation(rotation, context)
- insets = getCalculatedInsetsForRotation(rotation, rotatedResources)
- insetsByCorner[rotation] = insets
+ insets = getAndSetInsetsForRotation(rotation, rotatedResources)
}
return insets
@@ -157,13 +149,19 @@
}
private fun getCalculatedInsetsForRotation(
- @Rotation rotation: Int,
+ @Rotation targetRotation: Int,
rotatedResources: Resources
): Rect {
val dc = context.display.cutout
+ val currentRotation = RotationUtils.getExactRotation(context)
return calculateInsetsForRotationWithRotatedResources(
- rotation, rotatedResources, dc, windowManager, context)
+ currentRotation,
+ targetRotation,
+ dc,
+ windowManager.maximumWindowMetrics,
+ rotatedResources.getDimensionPixelSize(R.dimen.status_bar_height),
+ rotatedResources.getDimensionPixelSize(R.dimen.rounded_corner_content_padding))
}
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
@@ -179,8 +177,8 @@
private const val TAG = "StatusBarInsetsProvider"
-private fun getRotationZeroDisplayBounds(wm: WindowManager, @Rotation exactRotation: Int): Rect {
- val bounds = wm.maximumWindowMetrics.bounds
+private fun getRotationZeroDisplayBounds(wm: WindowMetrics, @Rotation exactRotation: Int): Rect {
+ val bounds = wm.bounds
if (exactRotation == ROTATION_NONE || exactRotation == ROTATION_UPSIDE_DOWN) {
return bounds
@@ -190,9 +188,24 @@
return Rect(0, 0, bounds.bottom, bounds.right)
}
-private fun getCurrentDisplayBounds(wm: WindowManager): Rect {
- val bounds = wm.maximumWindowMetrics.bounds
- return bounds
+@VisibleForTesting
+fun getPrivacyChipBoundingRectForInsets(
+ contentRect: Rect,
+ dotWidth: Int,
+ chipWidth: Int,
+ isRtl: Boolean
+): Rect {
+ return if (isRtl) {
+ Rect(contentRect.left - dotWidth,
+ contentRect.top,
+ contentRect.left + chipWidth,
+ contentRect.bottom)
+ } else {
+ Rect(contentRect.right - chipWidth,
+ contentRect.top,
+ contentRect.right + dotWidth,
+ contentRect.bottom)
+ }
}
/**
@@ -206,41 +219,32 @@
* @see [RotationUtils#getResourcesForRotation]
*/
fun calculateInsetsForRotationWithRotatedResources(
+ @Rotation currentRotation: Int,
@Rotation targetRotation: Int,
- rotatedResources: Resources,
displayCutout: DisplayCutout?,
- windowmanager: WindowManager,
- context: Context
+ windowMetrics: WindowMetrics,
+ statusBarHeight: Int,
+ roundedCornerPadding: Int
): Rect {
- val rtl = rotatedResources.configuration.layoutDirection == LAYOUT_DIRECTION_RTL
-
- val exactRotation = RotationUtils.getExactRotation(context)
- val height = rotatedResources.getDimensionPixelSize(R.dimen.status_bar_height)
-
/*
TODO: Check if this is ever used for devices with no rounded corners
- val paddingStart = rotatedResources.getDimensionPixelSize(R.dimen.status_bar_padding_start)
- val paddingEnd = rotatedResources.getDimensionPixelSize(R.dimen.status_bar_padding_end)
- val left = if (rtl) paddingEnd else paddingStart
- val right = if(rtl) paddingStart else paddingEnd
+ val left = if (isRtl) paddingEnd else paddingStart
+ val right = if (isRtl) paddingStart else paddingEnd
*/
- val roundedCornerPadding = rotatedResources.getDimensionPixelSize(
- R.dimen.rounded_corner_content_padding)
-
- val rotZeroBounds = getRotationZeroDisplayBounds(windowmanager, exactRotation)
- val currentBounds = getCurrentDisplayBounds(windowmanager)
+ val rotZeroBounds = getRotationZeroDisplayBounds(windowMetrics, currentRotation)
+ val currentBounds = windowMetrics.bounds
val sbLeftRight = getStatusBarLeftRight(
displayCutout,
- height,
+ statusBarHeight,
rotZeroBounds.right,
rotZeroBounds.bottom,
currentBounds.width(),
currentBounds.height(),
roundedCornerPadding,
targetRotation,
- exactRotation)
+ currentRotation)
return sbLeftRight
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index ebf2465..d3953df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -23,7 +23,6 @@
import android.util.Log;
import com.android.settingslib.mobile.TelephonyIcons;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.policy.NetworkController;
@@ -63,6 +62,7 @@
private final SecurityController mSecurityController;
private final Handler mHandler = Handler.getMain();
private final CarrierConfigTracker mCarrierConfigTracker;
+ private final TunerService mTunerService;
private boolean mHideAirplane;
private boolean mHideMobile;
@@ -83,9 +83,16 @@
@Inject
public StatusBarSignalPolicy(Context context, StatusBarIconController iconController,
- CarrierConfigTracker carrierConfigTracker) {
+ CarrierConfigTracker carrierConfigTracker, NetworkController networkController,
+ SecurityController securityController, TunerService tunerService) {
mContext = context;
+ mIconController = iconController;
+ mCarrierConfigTracker = carrierConfigTracker;
+ mNetworkController = networkController;
+ mSecurityController = securityController;
+ mTunerService = tunerService;
+
mSlotAirplane = mContext.getString(com.android.internal.R.string.status_bar_airplane);
mSlotMobile = mContext.getString(com.android.internal.R.string.status_bar_mobile);
mSlotWifi = mContext.getString(com.android.internal.R.string.status_bar_wifi);
@@ -96,18 +103,14 @@
mContext.getString(com.android.internal.R.string.status_bar_call_strength);
mActivityEnabled = mContext.getResources().getBoolean(R.bool.config_showActivity);
- mIconController = iconController;
- mCarrierConfigTracker = carrierConfigTracker;
- mNetworkController = Dependency.get(NetworkController.class);
- mSecurityController = Dependency.get(SecurityController.class);
- Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
+ tunerService.addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
mNetworkController.addCallback(this);
mSecurityController.addCallback(this);
}
public void destroy() {
- Dependency.get(TunerService.class).removeTunable(this);
+ mTunerService.removeTunable(this);
mNetworkController.removeCallback(this);
mSecurityController.removeCallback(this);
}
@@ -172,7 +175,7 @@
&& !mIsAirplaneMode) {
newState.visible = true;
newState.resId = R.drawable.ic_qs_no_internet_unavailable;
- } else if (mWifiIconState.noValidatedNetwork && !mWifiIconState.noNetworksAvailable
+ } else if (mWifiIconState.noDefaultNetwork && !mWifiIconState.noNetworksAvailable
&& (!mIsAirplaneMode || (mIsAirplaneMode && mIsWifiEnabled))) {
newState.visible = true;
newState.resId = R.drawable.ic_qs_no_internet_available;
@@ -377,7 +380,7 @@
if (noDefaultNetwork && noNetworksAvailable && !mIsAirplaneMode) {
newState.visible = true;
newState.resId = R.drawable.ic_qs_no_internet_unavailable;
- } else if (noValidatedNetwork && !noNetworksAvailable
+ } else if (noDefaultNetwork && !noNetworksAvailable
&& (!mIsAirplaneMode || (mIsAirplaneMode && mIsWifiEnabled))) {
newState.visible = true;
newState.resId = R.drawable.ic_qs_no_internet_available;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java
new file mode 100644
index 0000000..52e0e8a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.systemui.R;
+import com.android.wm.shell.animation.Interpolators;
+
+/**
+ * View to show a toast-like popup on the notification shade and quick settings.
+ */
+public class TapAgainView extends TextView {
+ private TextView mTextView;
+
+ public TapAgainView(
+ @NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ updateColor();
+ }
+
+ void updateColor() {
+ int textColor = getResources().getColor(R.color.notif_pill_text, mContext.getTheme());
+ setTextColor(textColor);
+ setBackground(getResources().getDrawable(R.drawable.rounded_bg_full, mContext.getTheme()));
+ }
+
+ /** Make the view visible. */
+ public void animateIn() {
+ int yTranslation = mContext.getResources().getDimensionPixelSize(
+ R.dimen.keyguard_indication_y_translation);
+
+ AnimatorSet animatorSet = new AnimatorSet();
+ ObjectAnimator fadeIn = ObjectAnimator.ofFloat(this, View.ALPHA, 1f);
+ fadeIn.setStartDelay(150); // From KeyguardIndicationTextView#getFadeInDelay
+ fadeIn.setDuration(317); // From KeyguardIndicationTextView#getFadeInDuration
+ fadeIn.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+
+ Animator yTranslate =
+ ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, yTranslation, 0);
+ yTranslate.setDuration(600); // From KeyguardIndicationTextView#getYInDuration
+ yTranslate.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ setTranslationY(0);
+ }
+ });
+ animatorSet.playTogether(yTranslate, fadeIn);
+ animatorSet.start();
+ setVisibility(View.VISIBLE);
+ }
+
+ /** Make the view gone. */
+ public void animateOut() {
+ long fadeOutDuration = 167L; // From KeyguardIndicationTextView#getFadeOutDuration
+ int yTranslation = mContext.getResources().getDimensionPixelSize(
+ com.android.systemui.R.dimen.keyguard_indication_y_translation);
+
+ AnimatorSet animatorSet = new AnimatorSet();
+ ObjectAnimator fadeOut = ObjectAnimator.ofFloat(this, View.ALPHA, 0f);
+ fadeOut.setDuration(fadeOutDuration);
+ fadeOut.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
+
+ Animator yTranslate =
+ ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, 0, -yTranslation);
+ yTranslate.setDuration(fadeOutDuration);
+ animatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ setVisibility(GONE);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ setVisibility(GONE);
+ }
+ });
+ animatorSet.playTogether(yTranslate, fadeOut);
+ animatorSet.start();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainViewController.java
new file mode 100644
index 0000000..0c5502b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainViewController.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static com.android.systemui.classifier.FalsingModule.DOUBLE_TAP_TIMEOUT_MS;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+import com.android.systemui.util.ViewController;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ * Controller for {@link TapAgainView}.
+ */
+@StatusBarComponent.StatusBarScope
+public class TapAgainViewController extends ViewController<TapAgainView> {
+ private final DelayableExecutor mDelayableExecutor;
+ private final ConfigurationController mConfigurationController;
+ private final long mDoubleTapTimeMs;
+
+ private Runnable mHideCanceler;
+
+ @VisibleForTesting
+ final ConfigurationListener mConfigurationListener = new ConfigurationListener() {
+ @Override
+ public void onOverlayChanged() {
+ mView.updateColor();
+ }
+
+ @Override
+ public void onUiModeChanged() {
+ mView.updateColor();
+ }
+
+ @Override
+ public void onThemeChanged() {
+ mView.updateColor();
+ }
+ };
+
+ @Inject
+ protected TapAgainViewController(TapAgainView view,
+ @Main DelayableExecutor delayableExecutor,
+ ConfigurationController configurationController,
+ @Named(DOUBLE_TAP_TIMEOUT_MS) long doubleTapTimeMs) {
+ super(view);
+ mDelayableExecutor = delayableExecutor;
+ mConfigurationController = configurationController;
+ mDoubleTapTimeMs = doubleTapTimeMs;
+ }
+
+ @Override
+ protected void onViewAttached() {
+ mConfigurationController.addCallback(mConfigurationListener);
+ }
+
+ @Override
+ protected void onViewDetached() {
+ mConfigurationController.removeCallback(mConfigurationListener);
+ }
+
+ /** Shows the associated view, possibly animating it. */
+ public void show() {
+ if (mHideCanceler != null) {
+ mHideCanceler.run();
+ }
+ mView.animateIn();
+ mHideCanceler = mDelayableExecutor.executeDelayed(this::hide, mDoubleTapTimeMs);
+ }
+
+ /** Hides the associated view, possibly animating it. */
+ public void hide() {
+ mHideCanceler = null;
+ mView.animateOut();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
index 008c0ae..27d71ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
@@ -23,6 +23,7 @@
import com.android.systemui.biometrics.AuthRippleView;
import com.android.systemui.statusbar.phone.NotificationPanelView;
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
+import com.android.systemui.statusbar.phone.TapAgainView;
import dagger.Module;
import dagger.Provides;
@@ -53,4 +54,11 @@
NotificationShadeWindowView notificationShadeWindowView) {
return notificationShadeWindowView.findViewById(R.id.auth_ripple);
}
+
+ /** */
+ @Provides
+ @StatusBarComponent.StatusBarScope
+ public static TapAgainView getTapAgainView(NotificationPanelView npv) {
+ return npv.getTapAgainView();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
index e7201f8..af7bf95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
@@ -50,6 +50,13 @@
boolean canDismissLockScreen();
/**
+ * Whether we can currently perform the shared element SmartSpace transition. This is true if
+ * we're on the lockscreen, it can be dismissed with a swipe, and the Launcher is underneath the
+ * keyguard and displaying a SmartSpace that it has registered with System UI.
+ */
+ boolean canPerformSmartSpaceTransition();
+
+ /**
* If the device has PIN/pattern/password or a lock screen at all.
*/
boolean isMethodSecure();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index e69c1f2..0945a3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -32,6 +32,7 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -53,6 +54,7 @@
private final LockPatternUtils mLockPatternUtils;
private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
new UpdateMonitorCallback();
+ private final SmartspaceTransitionController mSmartspaceTransitionController;
private boolean mCanDismissLockScreen;
private boolean mShowing;
@@ -96,10 +98,12 @@
*/
@Inject
public KeyguardStateControllerImpl(Context context,
- KeyguardUpdateMonitor keyguardUpdateMonitor, LockPatternUtils lockPatternUtils) {
+ KeyguardUpdateMonitor keyguardUpdateMonitor, LockPatternUtils lockPatternUtils,
+ SmartspaceTransitionController smartspaceTransitionController) {
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
+ mSmartspaceTransitionController = smartspaceTransitionController;
update(true /* updateAlways */);
if (Build.IS_DEBUGGABLE && DEBUG_AUTH_WITH_ADB) {
@@ -158,6 +162,11 @@
mShowing = showing;
mOccluded = occluded;
notifyKeyguardChanged();
+
+ // Update the dismiss amount to the full 0f/1f if we explicitly show or hide the keyguard.
+ // Otherwise, the dismiss amount could be left at a random value if we show/hide during a
+ // dismiss gesture, canceling the gesture.
+ notifyKeyguardDismissAmountChanged(showing ? 0f : 1f, false);
}
private void notifyKeyguardChanged() {
@@ -228,6 +237,12 @@
}
@Override
+ public boolean canPerformSmartSpaceTransition() {
+ return canDismissLockScreen()
+ && mSmartspaceTransitionController.isSmartspaceTransitionPossible();
+ }
+
+ @Override
public boolean isFaceAuthEnabled() {
return mFaceAuthEnabled;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 07e9fed..4ab07af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -1023,6 +1023,11 @@
mValidatedTransports.clear();
if (mLastDefaultNetworkCapabilities != null) {
for (int transportType : mLastDefaultNetworkCapabilities.getTransportTypes()) {
+ if (transportType != NetworkCapabilities.TRANSPORT_CELLULAR
+ && transportType != NetworkCapabilities.TRANSPORT_WIFI
+ && transportType != NetworkCapabilities.TRANSPORT_ETHERNET) {
+ continue;
+ }
if (transportType == NetworkCapabilities.TRANSPORT_CELLULAR
&& Utils.tryGetWifiInfoForVcn(mLastDefaultNetworkCapabilities) != null) {
mConnectedTransports.set(NetworkCapabilities.TRANSPORT_WIFI);
@@ -1045,11 +1050,15 @@
Log.d(TAG, "updateConnectivity: mValidatedTransports=" + mValidatedTransports);
}
- mInetCondition = !mValidatedTransports.isEmpty();
+ mInetCondition = mValidatedTransports.get(NetworkCapabilities.TRANSPORT_CELLULAR)
+ || mValidatedTransports.get(NetworkCapabilities.TRANSPORT_WIFI)
+ || mValidatedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET);
pushConnectivityToSignals();
if (mProviderModel) {
- mNoDefaultNetwork = mConnectedTransports.isEmpty();
+ mNoDefaultNetwork = !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_CELLULAR)
+ && !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_WIFI)
+ && !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET);
mCallbackHandler.setConnectivityStatus(mNoDefaultNetwork, !mInetCondition,
mNoNetworksAvailable);
for (int i = 0; i < mMobileSignalControllers.size(); i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
index 4284148..c5e35a4 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
@@ -22,16 +22,19 @@
import android.app.Application;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.UserHandle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
-import android.widget.ToastPresenter;
import com.android.internal.R;
import com.android.launcher3.icons.IconFactory;
@@ -52,7 +55,6 @@
private final String mPackageName;
private final int mUserId;
private final LayoutInflater mLayoutInflater;
- private final boolean mToastStyleEnabled;
final int mDefaultX = 0;
final int mDefaultHorizontalMargin = 0;
@@ -66,15 +68,14 @@
@Nullable private final Animator mOutAnimator;
SystemUIToast(LayoutInflater layoutInflater, Context context, CharSequence text,
- String packageName, int userId, boolean toastStyleEnabled, int orientation) {
+ String packageName, int userId, int orientation) {
this(layoutInflater, context, text, null, packageName, userId,
- toastStyleEnabled, orientation);
+ orientation);
}
SystemUIToast(LayoutInflater layoutInflater, Context context, CharSequence text,
ToastPlugin.Toast pluginToast, String packageName, int userId,
- boolean toastStyleEnabled, int orientation) {
- mToastStyleEnabled = toastStyleEnabled;
+ int orientation) {
mLayoutInflater = layoutInflater;
mContext = context;
mText = text;
@@ -167,23 +168,45 @@
return mPluginToast.getView();
}
- View toastView;
- if (mToastStyleEnabled) {
- toastView = mLayoutInflater.inflate(
+ final View toastView = mLayoutInflater.inflate(
com.android.systemui.R.layout.text_toast, null);
- ((TextView) toastView.findViewById(com.android.systemui.R.id.text)).setText(mText);
+ final TextView textView = toastView.findViewById(com.android.systemui.R.id.text);
+ final ImageView iconView = toastView.findViewById(com.android.systemui.R.id.icon);
+ textView.setText(mText);
- Drawable icon = getBadgedIcon(mContext, mPackageName, mUserId);
- if (icon == null) {
- toastView.findViewById(com.android.systemui.R.id.icon).setVisibility(View.GONE);
- } else {
- ((ImageView) toastView.findViewById(com.android.systemui.R.id.icon))
- .setImageDrawable(icon);
- }
- } else {
- toastView = ToastPresenter.getTextToastView(mContext, mText);
+ ApplicationInfo appInfo = null;
+ try {
+ appInfo = mContext.getPackageManager()
+ .getApplicationInfoAsUser(mPackageName, 0, mUserId);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Package name not found package=" + mPackageName
+ + " user=" + mUserId);
}
+ if (appInfo != null && appInfo.targetSdkVersion < Build.VERSION_CODES.S) {
+ // no two-line limit
+ textView.setMaxLines(Integer.MAX_VALUE);
+
+ // no app icon
+ toastView.findViewById(com.android.systemui.R.id.icon).setVisibility(View.GONE);
+ } else {
+ Drawable icon = getBadgedIcon(mContext, mPackageName, mUserId);
+ if (icon == null) {
+ iconView.setVisibility(View.GONE);
+ } else {
+ iconView.setImageDrawable(icon);
+ if (appInfo.labelRes != 0) {
+ try {
+ Resources res = mContext.getPackageManager().getResourcesForApplication(
+ appInfo,
+ new Configuration(mContext.getResources().getConfiguration()));
+ iconView.setContentDescription(res.getString(appInfo.labelRes));
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.d(TAG, "Cannot find application resources for icon label.");
+ }
+ }
+ }
+ }
return toastView;
}
@@ -205,18 +228,14 @@
return mPluginToast.getInAnimation();
}
- return mToastStyleEnabled
- ? ToastDefaultAnimation.Companion.toastIn(getView())
- : null;
+ return ToastDefaultAnimation.Companion.toastIn(getView());
}
private Animator createOutAnimator() {
if (isPluginToast() && mPluginToast.getOutAnimation() != null) {
return mPluginToast.getOutAnimation();
}
- return mToastStyleEnabled
- ? ToastDefaultAnimation.Companion.toastOut(getView())
- : null;
+ return ToastDefaultAnimation.Companion.toastOut(getView());
}
/**
@@ -225,6 +244,10 @@
*/
public static Drawable getBadgedIcon(@NonNull Context context, String packageName,
int userId) {
+ if (!(context.getApplicationContext() instanceof Application)) {
+ return null;
+ }
+
final ApplicationsState appState =
ApplicationsState.getInstance((Application) context.getApplicationContext());
if (!appState.isUserAdded(userId)) {
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java b/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java
index 8b782d4..148bffa 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java
@@ -27,7 +27,6 @@
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.ToastPlugin;
import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.statusbar.FeatureFlags;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -43,17 +42,14 @@
// only one ToastPlugin can be connected at a time.
private ToastPlugin mPlugin;
private final LayoutInflater mLayoutInflater;
- private final boolean mToastStyleEnabled;
@Inject
public ToastFactory(
LayoutInflater layoutInflater,
PluginManager pluginManager,
- DumpManager dumpManager,
- FeatureFlags featureFlags) {
+ DumpManager dumpManager) {
mLayoutInflater = layoutInflater;
dumpManager.registerDumpable("ToastFactory", this);
- mToastStyleEnabled = featureFlags.isToastStyleEnabled();
pluginManager.addPluginListener(
new PluginListener<ToastPlugin>() {
@Override
@@ -77,10 +73,10 @@
int userId, int orientation) {
if (isPluginAvailable()) {
return new SystemUIToast(mLayoutInflater, context, text, mPlugin.createToast(text,
- packageName, userId), packageName, userId, mToastStyleEnabled, orientation);
+ packageName, userId), packageName, userId, orientation);
}
return new SystemUIToast(mLayoutInflater, context, text, packageName, userId,
- mToastStyleEnabled, orientation);
+ orientation);
}
private boolean isPluginAvailable() {
@@ -91,6 +87,5 @@
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("ToastFactory:");
pw.println(" mAttachedPlugin=" + mPlugin);
- pw.println(" mToastStyleEnabled=" + mToastStyleEnabled);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
index 92ea1d0..42f6687 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
@@ -19,6 +19,7 @@
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -34,7 +35,8 @@
import android.view.accessibility.IAccessibilityManager;
import android.widget.ToastPresenter;
-import com.android.internal.annotations.VisibleForTesting;
+import androidx.annotation.VisibleForTesting;
+
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.CommandQueue;
@@ -60,11 +62,11 @@
private final AccessibilityManager mAccessibilityManager;
private final ToastFactory mToastFactory;
private final ToastLogger mToastLogger;
- private SystemUIToast mToast;
@Nullable private ToastPresenter mPresenter;
@Nullable private ITransientNotificationCallback mCallback;
private ToastOutAnimatorListener mToastOutAnimatorListener;
+ @VisibleForTesting SystemUIToast mToast;
private int mOrientation = ORIENTATION_PORTRAIT;
@Inject
@@ -191,7 +193,7 @@
/**
* Once the out animation for a toast is finished, start showing the next toast.
*/
- class ToastOutAnimatorListener implements Animator.AnimatorListener {
+ class ToastOutAnimatorListener extends AnimatorListenerAdapter {
final ToastPresenter mPrevPresenter;
final ITransientNotificationCallback mPrevCallback;
@Nullable Runnable mShowNextToastRunnable;
@@ -210,10 +212,6 @@
}
@Override
- public void onAnimationStart(Animator animation) {
- }
-
- @Override
public void onAnimationEnd(Animator animation) {
mPrevPresenter.hide(mPrevCallback);
if (mShowNextToastRunnable != null) {
@@ -221,15 +219,5 @@
}
mToastOutAnimatorListener = null;
}
-
- @Override
- public void onAnimationCancel(Animator animation) {
- onAnimationEnd(animation);
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) {
-
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactory.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactory.java
index 7a5ceb5..fbec9e7 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactory.java
@@ -30,12 +30,20 @@
*/
public interface ThreadFactory {
/**
+ * Returns a {@link Looper} running on a named thread.
+ *
+ * The thread is implicitly started and may be left running indefinitely, depending on the
+ * implementation. Assume this is the case and use responsibly.
+ */
+ Looper buildLooperOnNewThread(String threadName);
+
+ /**
* Returns a {@link Handler} running on a named thread.
*
* The thread is implicitly started and may be left running indefinitely, depending on the
* implementation. Assume this is the case and use responsibly.
*/
- Handler builderHandlerOnNewThread(String threadName);
+ Handler buildHandlerOnNewThread(String threadName);
/**
* Return an {@link java.util.concurrent.Executor} running on a named thread.
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactoryImpl.java
index 184b831..051f433 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactoryImpl.java
@@ -29,10 +29,15 @@
ThreadFactoryImpl() {}
@Override
- public Handler builderHandlerOnNewThread(String threadName) {
+ public Looper buildLooperOnNewThread(String threadName) {
HandlerThread handlerThread = new HandlerThread(threadName);
handlerThread.start();
- return new Handler(handlerThread.getLooper());
+ return handlerThread.getLooper();
+ }
+
+ @Override
+ public Handler buildHandlerOnNewThread(String threadName) {
+ return new Handler(buildLooperOnNewThread(threadName));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java b/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java
index b9b7730..0b2f004 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java
@@ -116,7 +116,7 @@
default:
throw new IllegalArgumentException("Unknown rotation: " + rot);
}
- Configuration c = context.getResources().getConfiguration();
+ Configuration c = new Configuration(context.getResources().getConfiguration());
c.orientation = orientation;
Context rotated = context.createConfigurationContext(c);
return rotated.getResources();
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 3aba7ca..a5ccc47 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -38,11 +38,9 @@
import android.media.session.MediaSession.Token;
import android.net.Uri;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.VibrationEffect;
import android.os.Vibrator;
@@ -66,9 +64,9 @@
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.qs.tiles.DndTile;
-import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.util.RingerModeLiveData;
import com.android.systemui.util.RingerModeTracker;
+import com.android.systemui.util.concurrency.ThreadFactory;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -80,8 +78,6 @@
import javax.inject.Inject;
-import dagger.Lazy;
-
/**
* Source of truth for all state / events related to the volume dialog. No presentation.
*
@@ -118,12 +114,13 @@
STREAMS.put(AudioSystem.STREAM_VOICE_CALL, R.string.stream_voice_call);
}
- private final HandlerThread mWorkerThread;
private final W mWorker;
private final Context mContext;
+ private final Looper mWorkerLooper;
+ private final PackageManager mPackageManager;
+ private final WakefulnessLifecycle mWakefulnessLifecycle;
private AudioManager mAudio;
private IAudioService mAudioService;
- private final Optional<Lazy<StatusBar>> mStatusBarOptionalLazy;
private final NotificationManager mNoMan;
private final SettingObserver mObserver;
private final Receiver mReceiver = new Receiver();
@@ -132,13 +129,13 @@
protected C mCallbacks = new C();
private final State mState = new State();
protected final MediaSessionsCallbacks mMediaSessionsCallbacksW = new MediaSessionsCallbacks();
- private final Vibrator mVibrator;
+ private final Optional<Vibrator> mVibrator;
private final boolean mHasVibrator;
private boolean mShowA11yStream;
private boolean mShowVolumeDialog;
private boolean mShowSafetyWarning;
private long mLastToggledRingerOn;
- private final NotificationManager mNotificationManager;
+ private boolean mDeviceInteractive;
private boolean mDestroyed;
private VolumePolicy mVolumePolicy;
@@ -149,26 +146,42 @@
protected final VC mVolumeController = new VC();
protected final BroadcastDispatcher mBroadcastDispatcher;
- @Inject
- public VolumeDialogControllerImpl(Context context, BroadcastDispatcher broadcastDispatcher,
- Optional<Lazy<StatusBar>> statusBarOptionalLazy, RingerModeTracker ringerModeTracker) {
- mContext = context.getApplicationContext();
- // TODO(b/150663459): remove this TV workaround once StatusBar is "unbound" on TVs
- if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
- mStatusBarOptionalLazy = Optional.empty();
- } else {
- mStatusBarOptionalLazy = statusBarOptionalLazy;
+ private final WakefulnessLifecycle.Observer mWakefullnessLifecycleObserver =
+ new WakefulnessLifecycle.Observer() {
+ @Override
+ public void onStartedWakingUp() {
+ mDeviceInteractive = true;
}
- mNotificationManager = (NotificationManager) mContext.getSystemService(
- Context.NOTIFICATION_SERVICE);
+
+ @Override
+ public void onFinishedGoingToSleep() {
+ mDeviceInteractive = false;
+ }
+ };
+
+ @Inject
+ public VolumeDialogControllerImpl(
+ Context context,
+ BroadcastDispatcher broadcastDispatcher,
+ RingerModeTracker ringerModeTracker,
+ ThreadFactory theadFactory,
+ AudioManager audioManager,
+ NotificationManager notificationManager,
+ Optional<Vibrator> optionalVibrator,
+ IAudioService iAudioService,
+ AccessibilityManager accessibilityManager,
+ PackageManager packageManager,
+ WakefulnessLifecycle wakefulnessLifecycle) {
+ mContext = context.getApplicationContext();
+ mPackageManager = packageManager;
+ mWakefulnessLifecycle = wakefulnessLifecycle;
Events.writeEvent(Events.EVENT_COLLECTION_STARTED);
- mWorkerThread = new HandlerThread(VolumeDialogControllerImpl.class.getSimpleName());
- mWorkerThread.start();
- mWorker = new W(mWorkerThread.getLooper());
- mMediaSessions = createMediaSessions(mContext, mWorkerThread.getLooper(),
- mMediaSessionsCallbacksW);
- mAudio = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- mNoMan = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ mWorkerLooper = theadFactory.buildLooperOnNewThread(
+ VolumeDialogControllerImpl.class.getSimpleName());
+ mWorker = new W(mWorkerLooper);
+ mMediaSessions = createMediaSessions(mContext, mWorkerLooper, mMediaSessionsCallbacksW);
+ mAudio = audioManager;
+ mNoMan = notificationManager;
mObserver = new SettingObserver(mWorker);
mRingerModeObservers = new RingerModeObservers(
(RingerModeLiveData) ringerModeTracker.getRingerMode(),
@@ -178,16 +191,17 @@
mBroadcastDispatcher = broadcastDispatcher;
mObserver.init();
mReceiver.init();
- mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
- mHasVibrator = mVibrator != null && mVibrator.hasVibrator();
- mAudioService = IAudioService.Stub.asInterface(
- ServiceManager.getService(Context.AUDIO_SERVICE));
+ mVibrator = optionalVibrator;
+ mHasVibrator = mVibrator.isPresent() && mVibrator.get().hasVibrator();
+ mAudioService = iAudioService;
- boolean accessibilityVolumeStreamActive = context.getSystemService(
- AccessibilityManager.class).isAccessibilityVolumeStreamActive();
+ boolean accessibilityVolumeStreamActive = accessibilityManager
+ .isAccessibilityVolumeStreamActive();
mVolumeController.setA11yMode(accessibilityVolumeStreamActive ?
VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME :
VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME);
+
+ mWakefulnessLifecycle.addObserver(mWakefullnessLifecycleObserver);
}
public AudioManager getAudioManager() {
@@ -203,7 +217,6 @@
mAudio.setVolumeController(mVolumeController);
} catch (SecurityException e) {
Log.w(TAG, "Unable to set the volume controller", e);
- return;
}
}
@@ -249,18 +262,6 @@
return new MediaSessions(context, looper, callbacks);
}
- public void destroy() {
- if (D.BUG) Log.d(TAG, "destroy");
- if (mDestroyed) return;
- mDestroyed = true;
- Events.writeEvent(Events.EVENT_COLLECTION_STOPPED);
- mMediaSessions.destroy();
- mObserver.destroy();
- mReceiver.destroy();
- mRingerModeObservers.destroy();
- mWorkerThread.quitSafely();
- }
-
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println(VolumeDialogControllerImpl.class.getSimpleName() + " state:");
pw.print(" mDestroyed: "); pw.println(mDestroyed);
@@ -383,9 +384,8 @@
}
public void vibrate(VibrationEffect effect) {
- if (mHasVibrator) {
- mVibrator.vibrate(effect, SONIFICIATION_VIBRATION_ATTRIBUTES);
- }
+ mVibrator.ifPresent(
+ vibrator -> vibrator.vibrate(effect, SONIFICIATION_VIBRATION_ATTRIBUTES));
}
public boolean hasVibrator() {
@@ -437,9 +437,8 @@
return;
}
- PackageManager packageManager = mContext.getPackageManager();
mCallbacks.onCaptionComponentStateChanged(
- packageManager.getComponentEnabledSetting(componentName)
+ mPackageManager.getComponentEnabledSetting(componentName)
== PackageManager.COMPONENT_ENABLED_STATE_ENABLED, fromTooltip);
} catch (Exception ex) {
Log.e(TAG,
@@ -466,17 +465,11 @@
}
private boolean shouldShowUI(int flags) {
- // if status bar isn't null, check if phone is in AOD, else check flags
- // since we could be using a different status bar
- return mStatusBarOptionalLazy.map(statusBarLazy -> {
- StatusBar statusBar = statusBarLazy.get();
- return statusBar.getWakefulnessState() != WakefulnessLifecycle.WAKEFULNESS_ASLEEP
- && statusBar.getWakefulnessState()
- != WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP
- && statusBar.isDeviceInteractive() && (flags & AudioManager.FLAG_SHOW_UI) != 0
- && mShowVolumeDialog;
- }).orElse(
- mShowVolumeDialog && (flags & AudioManager.FLAG_SHOW_UI) != 0);
+ int wakefulness = mWakefulnessLifecycle.getWakefulness();
+ return wakefulness != WakefulnessLifecycle.WAKEFULNESS_ASLEEP
+ && wakefulness != WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP
+ && mDeviceInteractive && (flags & AudioManager.FLAG_SHOW_UI) != 0
+ && mShowVolumeDialog;
}
boolean onVolumeChangedW(int stream, int flags) {
@@ -600,15 +593,15 @@
private boolean updateEffectsSuppressorW(ComponentName effectsSuppressor) {
if (Objects.equals(mState.effectsSuppressor, effectsSuppressor)) return false;
mState.effectsSuppressor = effectsSuppressor;
- mState.effectsSuppressorName = getApplicationName(mContext, mState.effectsSuppressor);
+ mState.effectsSuppressorName =
+ getApplicationName(mPackageManager, mState.effectsSuppressor);
Events.writeEvent(Events.EVENT_SUPPRESSOR_CHANGED, mState.effectsSuppressor,
mState.effectsSuppressorName);
return true;
}
- private static String getApplicationName(Context context, ComponentName component) {
+ private static String getApplicationName(PackageManager pm, ComponentName component) {
if (component == null) return null;
- final PackageManager pm = context.getPackageManager();
final String pkg = component.getPackageName();
try {
final ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
@@ -630,8 +623,7 @@
}
private boolean updateZenConfig() {
- final NotificationManager.Policy policy =
- mNotificationManager.getConsolidatedNotificationPolicy();
+ final NotificationManager.Policy policy = mNoMan.getConsolidatedNotificationPolicy();
boolean disallowAlarms = (policy.priorityCategories & NotificationManager.Policy
.PRIORITY_CATEGORY_ALARMS) == 0;
boolean disallowMedia = (policy.priorityCategories & NotificationManager.Policy
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 50b8858..961822a5 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -337,37 +337,44 @@
mTouchableRegion.setEmpty();
- // Set the touchable region to the union of all child view bounds. We don't use touches on
- // the volume dialog container itself, so this is fine.
+ // Set the touchable region to the union of all child view bounds and the live caption
+ // tooltip. We don't use touches on the volume dialog container itself, so this is fine.
for (int i = 0; i < mDialogView.getChildCount(); i++) {
- final View view = mDialogView.getChildAt(i);
- final int[] locInWindow = new int[2];
- view.getLocationInWindow(locInWindow);
+ unionViewBoundstoTouchableRegion(mDialogView.getChildAt(i));
+ }
- float x = locInWindow[0];
- float y = locInWindow[1];
-
- // The ringer and rows container has extra height at the top to fit the expanded ringer
- // drawer. This area should not be touchable unless the ringer drawer is open.
- if (view == mTopContainer && !mIsRingerDrawerOpen) {
- if (!isLandscape()) {
- y += getRingerDrawerOpenExtraSize();
- } else {
- x += getRingerDrawerOpenExtraSize();
- }
- }
-
- mTouchableRegion.op(
- (int) x,
- (int) y,
- locInWindow[0] + view.getWidth(),
- locInWindow[1] + view.getHeight(),
- Region.Op.UNION);
+ if (mODICaptionsTooltipView != null && mODICaptionsTooltipView.getVisibility() == VISIBLE) {
+ unionViewBoundstoTouchableRegion(mODICaptionsTooltipView);
}
internalInsetsInfo.touchableRegion.set(mTouchableRegion);
}
+ private void unionViewBoundstoTouchableRegion(final View view) {
+ final int[] locInWindow = new int[2];
+ view.getLocationInWindow(locInWindow);
+
+ float x = locInWindow[0];
+ float y = locInWindow[1];
+
+ // The ringer and rows container has extra height at the top to fit the expanded ringer
+ // drawer. This area should not be touchable unless the ringer drawer is open.
+ if (view == mTopContainer && !mIsRingerDrawerOpen) {
+ if (!isLandscape()) {
+ y += getRingerDrawerOpenExtraSize();
+ } else {
+ x += getRingerDrawerOpenExtraSize();
+ }
+ }
+
+ mTouchableRegion.op(
+ (int) x,
+ (int) y,
+ locInWindow[0] + view.getWidth(),
+ locInWindow[1] + view.getHeight(),
+ Region.Op.UNION);
+ }
+
private void initDialog() {
mDialog = new CustomDialog(mContext);
@@ -1058,21 +1065,38 @@
}
if (mODICaptionsTooltipView != null) {
- mODICaptionsTooltipView.setAlpha(0.f);
- mODICaptionsTooltipView.animate()
- .alpha(1.f)
- .setStartDelay(mDialogShowAnimationDurationMs)
- .withEndAction(() -> {
- if (D.BUG) Log.d(TAG, "tool:checkODICaptionsTooltip() putBoolean true");
- Prefs.putBoolean(mContext,
- Prefs.Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP, true);
- mHasSeenODICaptionsTooltip = true;
- if (mODICaptionsIcon != null) {
- mODICaptionsIcon
- .postOnAnimation(getSinglePressFor(mODICaptionsIcon));
- }
- })
- .start();
+ mODICaptionsTooltipView.setAlpha(0.0f);
+
+ // We need to wait for layout and then center the caption view. Since the height of the
+ // dialog is now dynamic (with the variable ringer drawer height changing the height of
+ // the dialog), we need to do this here in code vs. in XML.
+ mHandler.post(() -> {
+ final int[] odiTooltipLocation = mODICaptionsTooltipView.getLocationOnScreen();
+ final int[] odiButtonLocation = mODICaptionsIcon.getLocationOnScreen();
+
+ final float heightDiffForCentering =
+ (mODICaptionsTooltipView.getHeight() - mODICaptionsIcon.getHeight()) / 2f;
+
+ mODICaptionsTooltipView.setTranslationY(
+ odiButtonLocation[1] - odiTooltipLocation[1] - heightDiffForCentering);
+
+ mODICaptionsTooltipView.animate()
+ .alpha(1.0f)
+ .setStartDelay(mDialogShowAnimationDurationMs)
+ .withEndAction(() -> {
+ if (D.BUG) {
+ Log.d(TAG, "tool:checkODICaptionsTooltip() putBoolean true");
+ }
+ Prefs.putBoolean(mContext,
+ Prefs.Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP, true);
+ mHasSeenODICaptionsTooltip = true;
+ if (mODICaptionsIcon != null) {
+ mODICaptionsIcon
+ .postOnAnimation(getSinglePressFor(mODICaptionsIcon));
+ }
+ })
+ .start();
+ });
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
new file mode 100644
index 0000000..9d0cc6a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wallet.controller;
+
+import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE;
+import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.provider.Settings;
+import android.service.quickaccesswallet.GetWalletCardsRequest;
+import android.service.quickaccesswallet.QuickAccessWalletClient;
+import android.service.quickaccesswallet.QuickAccessWalletClientImpl;
+import android.util.Log;
+
+import com.android.systemui.R;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.util.settings.SecureSettings;
+
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
+/**
+ * Controller to handle communication between SystemUI and Quick Access Wallet Client.
+ */
+@SysUISingleton
+public class QuickAccessWalletController {
+
+ /**
+ * Event for the wallet status change, e.g. the default payment app change and the wallet
+ * preference change.
+ */
+ public enum WalletChangeEvent {
+ DEFAULT_PAYMENT_APP_CHANGE,
+ WALLET_PREFERENCE_CHANGE,
+ }
+
+ private static final String TAG = "QAWController";
+ private final Context mContext;
+ private final Executor mExecutor;
+ private final SecureSettings mSecureSettings;
+
+ private QuickAccessWalletClient mQuickAccessWalletClient;
+ private ContentObserver mWalletPreferenceObserver;
+ private ContentObserver mDefaultPaymentAppObserver;
+ private int mWalletPreferenceChangeEvents = 0;
+ private int mDefaultPaymentAppChangeEvents = 0;
+ private boolean mWalletEnabled = false;
+
+ @Inject
+ public QuickAccessWalletController(
+ Context context,
+ @Main Executor executor,
+ SecureSettings secureSettings,
+ QuickAccessWalletClient quickAccessWalletClient) {
+ mContext = context;
+ mExecutor = executor;
+ mSecureSettings = secureSettings;
+ mQuickAccessWalletClient = quickAccessWalletClient;
+ }
+
+ /**
+ * Returns true if the Quick Access Wallet service & feature is available.
+ */
+ public boolean isWalletEnabled() {
+ return mWalletEnabled;
+ }
+
+ /**
+ * Returns the current instance of {@link QuickAccessWalletClient} in the controller.
+ */
+ public QuickAccessWalletClient getWalletClient() {
+ return mQuickAccessWalletClient;
+ }
+
+ /**
+ * Setup the wallet change observers per {@link WalletChangeEvent}
+ *
+ * @param cardsRetriever a callback that retrieves the wallet cards
+ * @param events {@link WalletChangeEvent} need to be handled.
+ */
+ public void setupWalletChangeObservers(
+ QuickAccessWalletClient.OnWalletCardsRetrievedCallback cardsRetriever,
+ WalletChangeEvent... events) {
+ for (WalletChangeEvent event : events) {
+ if (event == WALLET_PREFERENCE_CHANGE) {
+ setupWalletPreferenceObserver();
+ } else if (event == DEFAULT_PAYMENT_APP_CHANGE) {
+ setupDefaultPaymentAppObserver(cardsRetriever);
+ }
+ }
+ }
+
+ /**
+ * Unregister wallet change observers per {@link WalletChangeEvent} if needed.
+ *
+ */
+ public void unregisterWalletChangeObservers(WalletChangeEvent... events) {
+ for (WalletChangeEvent event : events) {
+ if (event == WALLET_PREFERENCE_CHANGE && mWalletPreferenceObserver != null) {
+ mWalletPreferenceChangeEvents--;
+ if (mWalletPreferenceChangeEvents == 0) {
+ mSecureSettings.unregisterContentObserver(mWalletPreferenceObserver);
+ }
+ } else if (event == DEFAULT_PAYMENT_APP_CHANGE && mDefaultPaymentAppObserver != null) {
+ mDefaultPaymentAppChangeEvents--;
+ if (mDefaultPaymentAppChangeEvents == 0) {
+ mSecureSettings.unregisterContentObserver(mDefaultPaymentAppObserver);
+ }
+ }
+ }
+ }
+
+ /**
+ * Update the "show wallet" preference.
+ */
+ public void updateWalletPreference() {
+ mWalletEnabled = mQuickAccessWalletClient.isWalletServiceAvailable()
+ && mQuickAccessWalletClient.isWalletFeatureAvailable()
+ && mQuickAccessWalletClient.isWalletFeatureAvailableWhenDeviceLocked();
+ }
+
+ /**
+ * Query the wallet cards from {@link QuickAccessWalletClient}.
+ *
+ * @param cardsRetriever a callback to retrieve wallet cards.
+ */
+ public void queryWalletCards(
+ QuickAccessWalletClient.OnWalletCardsRetrievedCallback cardsRetriever) {
+ if (!mWalletEnabled) {
+ Log.w(TAG, "QuickAccessWallet is unavailable, unable to query cards.");
+ return;
+ }
+ int cardWidth =
+ mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_width);
+ int cardHeight =
+ mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_height);
+ int iconSizePx = mContext.getResources().getDimensionPixelSize(R.dimen.wallet_icon_size);
+ GetWalletCardsRequest request =
+ new GetWalletCardsRequest(cardWidth, cardHeight, iconSizePx, /* maxCards= */ 1);
+ mQuickAccessWalletClient.getWalletCards(mExecutor, request, cardsRetriever);
+ }
+
+ /**
+ * Re-create the {@link QuickAccessWalletClient} of the controller.
+ */
+ public void reCreateWalletClient() {
+ mQuickAccessWalletClient = QuickAccessWalletClient.create(mContext);
+ }
+
+ private void setupDefaultPaymentAppObserver(
+ QuickAccessWalletClient.OnWalletCardsRetrievedCallback cardsRetriever) {
+ if (mDefaultPaymentAppObserver == null) {
+ mDefaultPaymentAppObserver = new ContentObserver(null /* handler */) {
+ @Override
+ public void onChange(boolean selfChange) {
+ mExecutor.execute(() -> {
+ reCreateWalletClient();
+ updateWalletPreference();
+ queryWalletCards(cardsRetriever);
+ });
+ }
+ };
+
+ mSecureSettings.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT),
+ false /* notifyForDescendants */,
+ mDefaultPaymentAppObserver);
+ }
+ mDefaultPaymentAppChangeEvents++;
+ }
+
+ private void setupWalletPreferenceObserver() {
+ if (mWalletPreferenceObserver == null) {
+ mWalletPreferenceObserver = new ContentObserver(null /* handler */) {
+ @Override
+ public void onChange(boolean selfChange) {
+ mExecutor.execute(() -> {
+ updateWalletPreference();
+ });
+ }
+ };
+
+ mSecureSettings.registerContentObserver(
+ Settings.Secure.getUriFor(QuickAccessWalletClientImpl.SETTING_KEY),
+ false /* notifyForDescendants */,
+ mWalletPreferenceObserver);
+ }
+ mWalletPreferenceChangeEvents++;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
index 83aa01f..c6123e7 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
@@ -24,6 +24,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.service.quickaccesswallet.QuickAccessWalletClient;
+import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.Window;
@@ -52,7 +53,7 @@
*/
public class WalletActivity extends LifecycleActivity {
- private final QuickAccessWalletClient mQuickAccessWalletClient;
+ private static final String TAG = "WalletActivity";
private final KeyguardStateController mKeyguardStateController;
private final KeyguardDismissUtil mKeyguardDismissUtil;
private final ActivityStarter mActivityStarter;
@@ -65,7 +66,6 @@
@Inject
public WalletActivity(
- QuickAccessWalletClient quickAccessWalletClient,
KeyguardStateController keyguardStateController,
KeyguardDismissUtil keyguardDismissUtil,
ActivityStarter activityStarter,
@@ -74,7 +74,6 @@
FalsingManager falsingManager,
UserTracker userTracker,
StatusBarKeyguardViewManager keyguardViewManager) {
- mQuickAccessWalletClient = quickAccessWalletClient;
mKeyguardStateController = keyguardStateController;
mKeyguardDismissUtil = keyguardDismissUtil;
mActivityStarter = activityStarter;
@@ -103,10 +102,11 @@
getActionBar().setHomeActionContentDescription(R.string.accessibility_desc_close);
WalletView walletView = requireViewById(R.id.wallet_view);
+ QuickAccessWalletClient walletClient = QuickAccessWalletClient.create(this);
mWalletScreenController = new WalletScreenController(
this,
walletView,
- mQuickAccessWalletClient,
+ walletClient,
mActivityStarter,
mExecutor,
mHandler,
@@ -116,6 +116,10 @@
walletView.getAppButton().setOnClickListener(
v -> {
+ if (walletClient.createWalletIntent() == null) {
+ Log.w(TAG, "Unable to create wallet app intent.");
+ return;
+ }
if (!mKeyguardStateController.isUnlocked()
&& mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
return;
@@ -123,12 +127,12 @@
if (mKeyguardStateController.isUnlocked()) {
mActivityStarter.startActivity(
- mQuickAccessWalletClient.createWalletIntent(), true);
+ walletClient.createWalletIntent(), true);
finish();
} else {
mKeyguardDismissUtil.executeWhenUnlocked(() -> {
mActivityStarter.startActivity(
- mQuickAccessWalletClient.createWalletIntent(), true);
+ walletClient.createWalletIntent(), true);
finish();
return false;
}, false, true);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 10322f2..06b0bb2 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -40,8 +40,10 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -86,6 +88,9 @@
@Mock
Resources mResources;
+ KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ @Mock
+ SmartspaceTransitionController mSmartSpaceTransitionController;
@Mock
private ClockPlugin mClockPlugin;
@Mock
@@ -135,7 +140,10 @@
mBatteryController,
mKeyguardUpdateMonitor,
mBypassController,
- mSmartspaceController);
+ mSmartspaceController,
+ mKeyguardUnlockAnimationController,
+ mSmartSpaceTransitionController
+ );
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
when(mColorExtractor.getColors(anyInt())).thenReturn(mGradientColors);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index 49f1655..f9b6d44 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -22,6 +22,8 @@
import android.testing.AndroidTestingRunner;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -50,6 +52,10 @@
ConfigurationController mConfigurationController;
@Mock
DozeParameters mDozeParameters;
+ @Mock
+ KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ @Mock
+ SmartspaceTransitionController mSmartSpaceTransitionController;
private KeyguardStatusViewController mController;
@@ -64,7 +70,9 @@
mKeyguardStateController,
mKeyguardUpdateMonitor,
mConfigurationController,
- mDozeParameters);
+ mDozeParameters,
+ mKeyguardUnlockAnimationController,
+ mSmartSpaceTransitionController);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
index c6aef4a..bf87a4a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
@@ -20,6 +20,7 @@
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.ViewGroup
+import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.controls.controller.ControlsControllerImplTest.Companion.eq
@@ -33,6 +34,7 @@
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.animation.UniqueObjectHostView
+import junit.framework.Assert
import org.junit.Assert.assertNotNull
import org.junit.Before
import org.junit.Rule
@@ -65,8 +67,6 @@
@Mock
private lateinit var bypassController: KeyguardBypassController
@Mock
- private lateinit var mediaFrame: ViewGroup
- @Mock
private lateinit var keyguardStateController: KeyguardStateController
@Mock
private lateinit var statusBarStateController: SysuiStatusBarStateController
@@ -90,9 +90,11 @@
@Rule
val mockito = MockitoJUnit.rule()
private lateinit var mediaHiearchyManager: MediaHierarchyManager
+ private lateinit var mediaFrame: ViewGroup
@Before
fun setup() {
+ mediaFrame = FrameLayout(context)
`when`(mediaCarouselController.mediaFrame).thenReturn(mediaFrame)
mediaHiearchyManager = MediaHierarchyManager(
context,
@@ -112,6 +114,9 @@
`when`(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
`when`(mediaCarouselController.mediaCarouselScrollHandler)
.thenReturn(mediaCarouselScrollHandler)
+ val observer = wakefullnessObserver.value
+ assertNotNull("lifecycle observer wasn't registered", observer)
+ observer.onFinishedWakingUp()
// We'll use the viewmanager to verify a few calls below, let's reset this.
clearInvocations(mediaCarouselController)
}
@@ -120,6 +125,7 @@
`when`(host.location).thenReturn(location)
`when`(host.currentBounds).thenReturn(Rect())
`when`(host.hostView).thenReturn(UniqueObjectHostView(context))
+ `when`(host.visible).thenReturn(true)
mediaHiearchyManager.register(host)
}
@@ -160,6 +166,73 @@
}
@Test
+ fun testGoingToFullShade() {
+ // Let's set it onto Lock screen
+ `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+ `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(
+ true)
+ statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD)
+ clearInvocations(mediaCarouselController)
+
+ // Let's transition all the way to full shade
+ mediaHiearchyManager.setTransitionToFullShadeAmount(100000f)
+ verify(mediaCarouselController).onDesiredLocationChanged(
+ eq(MediaHierarchyManager.LOCATION_QQS),
+ any(MediaHostState::class.java),
+ eq(false),
+ anyLong(),
+ anyLong())
+ clearInvocations(mediaCarouselController)
+
+ // Let's go back to the lock screen
+ mediaHiearchyManager.setTransitionToFullShadeAmount(0.0f)
+ verify(mediaCarouselController).onDesiredLocationChanged(
+ eq(MediaHierarchyManager.LOCATION_LOCKSCREEN),
+ any(MediaHostState::class.java),
+ eq(false),
+ anyLong(),
+ anyLong())
+
+ // Let's make sure alpha is set
+ mediaHiearchyManager.setTransitionToFullShadeAmount(2.0f)
+ Assert.assertTrue("alpha should not be 1.0f when cross fading", mediaFrame.alpha != 1.0f)
+ }
+
+ @Test
+ fun testTransformationOnLockScreenIsFading() {
+ // Let's set it onto Lock screen
+ `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+ `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(
+ true)
+ statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD)
+ clearInvocations(mediaCarouselController)
+
+ // Let's transition from lockscreen to qs
+ mediaHiearchyManager.qsExpansion = 1.0f
+ val transformType = mediaHiearchyManager.calculateTransformationType()
+ Assert.assertTrue("media isn't transforming to qs with a fade",
+ transformType == MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
+ }
+
+ @Test
+ fun testTransformationOnLockScreenToQQSisFading() {
+ // Let's set it onto Lock screen
+ `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+ `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(
+ true)
+ statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD)
+ clearInvocations(mediaCarouselController)
+
+ // Let's transition from lockscreen to qs
+ `when`(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
+ statusBarCallback.value.onStatePreChange(StatusBarState.KEYGUARD,
+ StatusBarState.SHADE_LOCKED)
+ val transformType = mediaHiearchyManager.calculateTransformationType()
+ Assert.assertTrue("media isn't transforming to qqswith a fade",
+ transformType == MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
+ }
+
+ @Test
fun testCloseGutsRelayToCarousel() {
mediaHiearchyManager.closeGuts()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
index 96d1d94..4e1627f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
@@ -89,6 +89,7 @@
@Mock private lateinit var dumpManager: DumpManager
@Captor lateinit var callbackCaptor: ArgumentCaptor<ResumeMediaBrowser.Callback>
+ @Captor lateinit var actionCaptor: ArgumentCaptor<Runnable>
private lateinit var executor: FakeExecutor
private lateinit var data: MediaData
@@ -224,9 +225,6 @@
// But we do not tell it to add new controls
verify(mediaDataManager, never())
.addResumptionControls(anyInt(), any(), any(), any(), any(), any(), any())
-
- // Finally, make sure the resume browser disconnected
- verify(resumeBrowser).disconnect()
}
@Test
@@ -267,4 +265,39 @@
verify(mediaDataManager, times(3)).addResumptionControls(anyInt(),
any(), any(), any(), any(), any(), eq(PACKAGE_NAME))
}
+
+ @Test
+ fun testGetResumeAction_restarts() {
+ // Set up mocks to successfully find a MBS that returns valid media
+ val pm = mock(PackageManager::class.java)
+ whenever(mockContext.packageManager).thenReturn(pm)
+ val resolveInfo = ResolveInfo()
+ val serviceInfo = ServiceInfo()
+ serviceInfo.packageName = PACKAGE_NAME
+ resolveInfo.serviceInfo = serviceInfo
+ resolveInfo.serviceInfo.name = CLASS_NAME
+ val resumeInfo = listOf(resolveInfo)
+ whenever(pm.queryIntentServices(any(), anyInt())).thenReturn(resumeInfo)
+
+ val description = MediaDescription.Builder().setTitle(TITLE).build()
+ val component = ComponentName(PACKAGE_NAME, CLASS_NAME)
+ whenever(resumeBrowser.testConnection()).thenAnswer {
+ callbackCaptor.value.addTrack(description, component, resumeBrowser)
+ }
+
+ // When media data is loaded that has not been checked yet, and does have a MBS
+ val dataCopy = data.copy(resumeAction = null, hasCheckedForResume = false)
+ resumeListener.onMediaDataLoaded(KEY, null, dataCopy)
+
+ // Then we test whether the service is valid and set the resume action
+ executor.runAllReady()
+ verify(resumeBrowser).testConnection()
+ verify(mediaDataManager).setResumeAction(eq(KEY), capture(actionCaptor))
+
+ // When the resume action is run
+ actionCaptor.value.run()
+
+ // Then we call restart
+ verify(resumeBrowser).restart()
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt
index d26229e..dfa7c66 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt
@@ -91,8 +91,9 @@
setupBrowserFailed()
resumeBrowser.testConnection()
- // Then it calls onError
+ // Then it calls onError and disconnects
verify(callback).onError()
+ verify(browser).disconnect()
}
@Test
@@ -111,8 +112,9 @@
setupBrowserConnectionNoResults()
resumeBrowser.testConnection()
- // Then it calls onError
+ // Then it calls onError and disconnects
verify(callback).onError()
+ verify(browser).disconnect()
}
@Test
@@ -132,8 +134,9 @@
setupBrowserFailed()
resumeBrowser.findRecentMedia()
- // Then it calls onError
+ // Then it calls onError and disconnects
verify(callback).onError()
+ verify(browser).disconnect()
}
@Test
@@ -143,8 +146,9 @@
whenever(browser.getRoot()).thenReturn(null)
resumeBrowser.findRecentMedia()
- // Then it calls onError
+ // Then it calls onError and disconnects
verify(callback).onError()
+ verify(browser).disconnect()
}
@Test
@@ -163,8 +167,9 @@
setupBrowserConnectionNoResults()
resumeBrowser.findRecentMedia()
- // Then it calls onError
+ // Then it calls onError and disconnects
verify(callback).onError()
+ verify(browser).disconnect()
}
@Test
@@ -173,8 +178,9 @@
setupBrowserConnectionNotPlayable()
resumeBrowser.findRecentMedia()
- // Then it calls onError
+ // Then it calls onError and disconnects
verify(callback).onError()
+ verify(browser).disconnect()
}
@Test
@@ -193,8 +199,9 @@
setupBrowserFailed()
resumeBrowser.restart()
- // Then it calls onError
+ // Then it calls onError and disconnects
verify(callback).onError()
+ verify(browser).disconnect()
}
@Test
@@ -202,13 +209,11 @@
// When restart is called and we connect successfully
setupBrowserConnection()
resumeBrowser.restart()
+ verify(callback).onConnected()
// Then it creates a new controller and sends play command
verify(transportControls).prepare()
verify(transportControls).play()
-
- // Then it calls onConnected
- verify(callback).onConnected()
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
index 7533cf1..b09afab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
@@ -73,6 +73,7 @@
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.google.common.util.concurrent.MoreExecutors;
@@ -119,6 +120,8 @@
@Mock
private SecureSettings mSecureSettings;
@Mock
+ private QuickAccessWalletController mController;
+ @Mock
private FeatureFlags mFeatureFlags;
@Captor
ArgumentCaptor<Intent> mIntentCaptor;
@@ -145,6 +148,8 @@
when(mQuickAccessWalletClient.getServiceLabel()).thenReturn(LABEL);
when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(true);
when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(true);
+ when(mQuickAccessWalletClient.isWalletFeatureAvailableWhenDeviceLocked()).thenReturn(true);
+ when(mController.getWalletClient()).thenReturn(mQuickAccessWalletClient);
mTile = new QuickAccessWalletTile(
mHost,
@@ -155,11 +160,11 @@
mStatusBarStateController,
mActivityStarter,
mQSLogger,
- mQuickAccessWalletClient,
mKeyguardStateController,
mPackageManager,
mSecureSettings,
MoreExecutors.directExecutor(),
+ mController,
mFeatureFlags);
}
@@ -175,6 +180,15 @@
}
@Test
+ public void testWalletServiceUnavailable_recreateWalletClient() {
+ when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(false);
+
+ mTile.handleSetListening(true);
+
+ verify(mController, times(1)).reCreateWalletClient();
+ }
+
+ @Test
public void testIsAvailable_qawFeatureAvailable() {
when(mPackageManager.hasSystemFeature(FEATURE_NFC_HOST_CARD_EMULATION)).thenReturn(true);
when(mPackageManager.hasSystemFeature("org.chromium.arc")).thenReturn(false);
@@ -330,17 +344,8 @@
public void testHandleSetListening_queryCards() {
mTile.handleSetListening(true);
- verify(mQuickAccessWalletClient)
- .getWalletCards(any(), mRequestCaptor.capture(), mCallbackCaptor.capture());
+ verify(mController).queryWalletCards(mCallbackCaptor.capture());
- GetWalletCardsRequest request = mRequestCaptor.getValue();
- assertEquals(
- mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_width),
- request.getCardWidthPx());
- assertEquals(
- mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_height),
- request.getCardHeightPx());
- assertEquals(1, request.getMaxCards());
assertThat(mCallbackCaptor.getValue()).isInstanceOf(
QuickAccessWalletClient.OnWalletCardsRetrievedCallback.class);
}
@@ -354,37 +359,6 @@
}
@Test
- public void testState_queryCards_hasCards_then_noCards() {
- when(mKeyguardStateController.isUnlocked()).thenReturn(true);
- GetWalletCardsResponse responseWithCards =
- new GetWalletCardsResponse(
- Collections.singletonList(createWalletCard(mContext)), 0);
- GetWalletCardsResponse responseWithoutCards =
- new GetWalletCardsResponse(Collections.EMPTY_LIST, 0);
-
- mTile.handleSetListening(true);
-
- verify(mQuickAccessWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
-
- // query wallet cards, has cards
- mCallbackCaptor.getValue().onWalletCardsRetrieved(responseWithCards);
- mTestableLooper.processAllMessages();
-
- assertNotNull(mTile.getState().sideViewCustomDrawable);
-
- mTile.handleSetListening(true);
-
- verify(mQuickAccessWalletClient, times(2))
- .getWalletCards(any(), any(), mCallbackCaptor.capture());
-
- // query wallet cards, has no cards
- mCallbackCaptor.getValue().onWalletCardsRetrieved(responseWithoutCards);
- mTestableLooper.processAllMessages();
-
- assertNull(mTile.getState().sideViewCustomDrawable);
- }
-
- @Test
public void testQueryCards_noCards_notUpdateSideViewDrawable() {
setUpWalletCard(/* hasCard= */ false);
@@ -398,7 +372,7 @@
mTile.handleSetListening(true);
- verify(mQuickAccessWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
+ verify(mController).queryWalletCards(mCallbackCaptor.capture());
mCallbackCaptor.getValue().onWalletCardRetrievalError(error);
mTestableLooper.processAllMessages();
@@ -422,7 +396,7 @@
mTile.handleSetListening(true);
- verify(mQuickAccessWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
+ verify(mController).queryWalletCards(mCallbackCaptor.capture());
mCallbackCaptor.getValue().onWalletCardsRetrieved(response);
mTestableLooper.processAllMessages();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
index 9b5c33d..116f807 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
@@ -511,6 +511,9 @@
override fun setNextAlarm(image: Drawable?, description: String?) {
}
+
+ override fun setMediaTarget(target: SmartspaceTarget?) {
+ }
})
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 6b4797f..ee8d120 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -20,12 +20,15 @@
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
+import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED;
+import static com.android.systemui.statusbar.notification.ViewGroupFadeHelper.reset;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -39,7 +42,6 @@
import android.hardware.biometrics.BiometricSourceType;
import android.os.PowerManager;
import android.os.UserManager;
-import android.service.quickaccesswallet.QuickAccessWalletClient;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.DisplayMetrics;
@@ -75,13 +77,17 @@
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.doze.DozeLog;
+import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.fragments.FragmentService;
import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.MediaHierarchyManager;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.qs.QSDetailDisplayer;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.KeyguardAffordanceView;
+import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -105,6 +111,7 @@
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.time.FakeSystemClock;
+import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.android.wm.shell.animation.FlingAnimationUtils;
import org.junit.Before;
@@ -245,18 +252,28 @@
@Mock
private LockIconViewController mLockIconViewController;
@Mock
- private QuickAccessWalletClient mQuickAccessWalletClient;
- @Mock
private KeyguardMediaController mKeyguardMediaController;
@Mock
private PrivacyDotViewController mPrivacyDotViewController;
@Mock
private SecureSettings mSecureSettings;
+ @Mock
+ private TapAgainViewController mTapAgainViewController;
+ @Mock
+ private KeyguardIndicationController mKeyguardIndicationController;
+ @Mock
+ private FragmentService mFragmentService;
+ @Mock
+ private FragmentHostManager mFragmentHostManager;
+ @Mock
+ private QuickAccessWalletController mQuickAccessWalletController;
private SysuiStatusBarStateController mStatusBarStateController;
private NotificationPanelViewController mNotificationPanelViewController;
private View.AccessibilityDelegate mAccessibiltyDelegate;
private NotificationsQuickSettingsContainer mNotificationContainerParent;
+ private List<View.OnAttachStateChangeListener> mOnAttachStateChangeListeners;
+ private FalsingManagerFake mFalsingManager = new FalsingManagerFake();
@Before
public void setup() {
@@ -297,6 +314,7 @@
mNotificationContainerParent.addView(newViewWithId(R.id.keyguard_status_view));
when(mView.findViewById(R.id.notification_container_parent))
.thenReturn(mNotificationContainerParent);
+ when(mFragmentService.getFragmentHostManager(mView)).thenReturn(mFragmentHostManager);
FlingAnimationUtils.Builder flingAnimationUtilsBuilder = new FlingAnimationUtils.Builder(
mDisplayMetrics);
@@ -317,7 +335,7 @@
mKeyguardBypassController, mHeadsUpManager,
mock(NotificationRoundnessManager.class),
mStatusBarStateController,
- new FalsingManagerFake(),
+ mFalsingManager,
mLockscreenShadeTransitionController,
new FalsingCollectorFake());
when(mKeyguardStatusViewComponentFactory.build(any()))
@@ -331,11 +349,12 @@
when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController())
.thenReturn(mKeyguardStatusBarViewController);
+ reset(mView);
mNotificationPanelViewController = new NotificationPanelViewController(mView,
mResources,
mLayoutInflater,
coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
- new FalsingManagerFake(), new FalsingCollectorFake(),
+ mFalsingManager, new FalsingCollectorFake(),
mNotificationLockscreenUserManager, mNotificationEntryManager,
mKeyguardStateController, mStatusBarStateController, mDozeLog,
mDozeParameters, mCommandQueue, mVibratorHelper,
@@ -361,9 +380,11 @@
mAmbientState,
mLockIconViewController,
mFeatureFlags,
- mQuickAccessWalletClient,
mKeyguardMediaController,
mPrivacyDotViewController,
+ mTapAgainViewController,
+ mFragmentService,
+ mQuickAccessWalletController,
new FakeExecutor(new FakeSystemClock()),
mSecureSettings);
mNotificationPanelViewController.initDependencies(
@@ -371,6 +392,13 @@
mNotificationShelfController);
mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager);
mNotificationPanelViewController.setBar(mPanelBar);
+ mNotificationPanelViewController.setKeyguardIndicationController(
+ mKeyguardIndicationController);
+ ArgumentCaptor<View.OnAttachStateChangeListener> onAttachStateChangeListenerArgumentCaptor =
+ ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
+ verify(mView, atLeast(1)).addOnAttachStateChangeListener(
+ onAttachStateChangeListenerArgumentCaptor.capture());
+ mOnAttachStateChangeListeners = onAttachStateChangeListenerArgumentCaptor.getAllValues();
ArgumentCaptor<View.AccessibilityDelegate> accessibilityDelegateArgumentCaptor =
ArgumentCaptor.forClass(View.AccessibilityDelegate.class);
@@ -616,6 +644,34 @@
verify(mKeyguardStateController).notifyPanelFlingEnd();
}
+ @Test
+ public void testDoubleTapRequired_Keyguard() {
+ FalsingManager.FalsingTapListener listener = getFalsingTapListener();
+ mStatusBarStateController.setState(KEYGUARD);
+
+ listener.onDoubleTapRequired();
+
+ verify(mKeyguardIndicationController).showTransientIndication(anyInt());
+ }
+
+ @Test
+ public void testDoubleTapRequired_ShadeLocked() {
+ FalsingManager.FalsingTapListener listener = getFalsingTapListener();
+ mStatusBarStateController.setState(SHADE_LOCKED);
+
+ listener.onDoubleTapRequired();
+
+ verify(mTapAgainViewController).show();
+ }
+
+ private FalsingManager.FalsingTapListener getFalsingTapListener() {
+ for (View.OnAttachStateChangeListener listener : mOnAttachStateChangeListeners) {
+ listener.onViewAttachedToWindow(mView);
+ }
+ assertThat(mFalsingManager.getTapListeners().size()).isEqualTo(1);
+ return mFalsingManager.getTapListeners().get(0);
+ }
+
private View newViewWithId(int id) {
View view = new View(mContext);
view.setId(id);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
new file mode 100644
index 0000000..4796cd7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone
+
+import android.graphics.Rect
+import android.test.suitebuilder.annotation.SmallTest
+import android.view.DisplayCutout
+import android.view.WindowMetrics
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.leak.RotationUtils
+import com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE
+import com.android.systemui.util.leak.RotationUtils.ROTATION_NONE
+import com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE
+import com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN
+import com.android.systemui.util.leak.RotationUtils.Rotation
+import junit.framework.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class StatusBarContentInsetsProviderTest : SysuiTestCase() {
+ @Mock private lateinit var dc: DisplayCutout
+ @Mock private lateinit var windowMetrics: WindowMetrics
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ }
+
+ @Test
+ fun testGetBoundingRectForPrivacyChipForRotation_noCutout() {
+ val screenBounds = Rect(0, 0, 1080, 2160)
+ val roundedCornerPadding = 20
+ val sbHeightPortrait = 100
+ val sbHeightLandscape = 60
+ val currentRotation = ROTATION_NONE
+ val chipWidth = 30
+ val dotWidth = 10
+
+ `when`(windowMetrics.bounds).thenReturn(screenBounds)
+
+ var isRtl = false
+ var targetRotation = ROTATION_NONE
+ var bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ null,
+ windowMetrics,
+ sbHeightPortrait,
+ roundedCornerPadding)
+
+ var chipBounds = getPrivacyChipBoundingRectForInsets(bounds, dotWidth, chipWidth, isRtl)
+ /* 1080 - 20 (rounded corner) - 30 (chip),
+ * 0 (sb top)
+ * 1080 - 20 (rounded corner) + 10 ( dot),
+ * 100 (sb height portrait)
+ */
+ var expected = Rect(1030, 0, 1070, 100)
+ assertRects(expected, chipBounds, currentRotation, targetRotation)
+ isRtl = true
+ chipBounds = getPrivacyChipBoundingRectForInsets(bounds, dotWidth, chipWidth, isRtl)
+ /* 0 + 20 (rounded corner) - 10 (dot),
+ * 0 (sb top)
+ * 0 + 20 (rounded corner) + 30 (chip),
+ * 100 (sb height portrait)
+ */
+ expected = Rect(10, 0, 50, 100)
+ assertRects(expected, chipBounds, currentRotation, targetRotation)
+
+ isRtl = false
+ targetRotation = ROTATION_LANDSCAPE
+ bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ dc,
+ windowMetrics,
+ sbHeightLandscape,
+ roundedCornerPadding)
+
+ chipBounds = getPrivacyChipBoundingRectForInsets(bounds, dotWidth, chipWidth, isRtl)
+ /* 2160 - 20 (rounded corner) - 30 (chip),
+ * 0 (sb top)
+ * 2160 - 20 (rounded corner) + 10 ( dot),
+ * 60 (sb height landscape)
+ */
+ expected = Rect(2110, 0, 2150, 60)
+ assertRects(expected, chipBounds, currentRotation, targetRotation)
+ isRtl = true
+ chipBounds = getPrivacyChipBoundingRectForInsets(bounds, dotWidth, chipWidth, isRtl)
+ /* 0 + 20 (rounded corner) - 10 (dot),
+ * 0 (sb top)
+ * 0 + 20 (rounded corner) + 30 (chip),
+ * 60 (sb height landscape)
+ */
+ expected = Rect(10, 0, 50, 60)
+ assertRects(expected, chipBounds, currentRotation, targetRotation)
+ }
+
+ @Test
+ fun testCalculateInsetsForRotationWithRotatedResources_topLeftCutout() {
+ // GIVEN a device in portrait mode with width < height and a display cutout in the top-left
+ val screenBounds = Rect(0, 0, 1080, 2160)
+ val dcBounds = Rect(0, 0, 100, 100)
+ val roundedCornerPadding = 20
+ val sbHeightPortrait = 100
+ val sbHeightLandscape = 60
+ val currentRotation = ROTATION_NONE
+
+ `when`(windowMetrics.bounds).thenReturn(screenBounds)
+ `when`(dc.boundingRects).thenReturn(listOf(dcBounds))
+
+ // THEN rotations which share a short side should use the greater value between rounded
+ // corner padding and the display cutout's size
+ var targetRotation = ROTATION_NONE
+ var expectedBounds = Rect(dcBounds.right,
+ 0,
+ screenBounds.right - roundedCornerPadding,
+ sbHeightPortrait)
+
+ var bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ dc,
+ windowMetrics,
+ sbHeightPortrait,
+ roundedCornerPadding)
+
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+
+ targetRotation = ROTATION_LANDSCAPE
+ expectedBounds = Rect(dcBounds.height(),
+ 0,
+ screenBounds.height() - roundedCornerPadding,
+ sbHeightLandscape)
+
+ bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ dc,
+ windowMetrics,
+ sbHeightLandscape,
+ roundedCornerPadding)
+
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+
+ // THEN the side that does NOT share a short side with the display cutout ignores the
+ // display cutout bounds
+ targetRotation = ROTATION_UPSIDE_DOWN
+ expectedBounds = Rect(roundedCornerPadding,
+ 0,
+ screenBounds.width() - roundedCornerPadding,
+ sbHeightPortrait)
+
+ bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ dc,
+ windowMetrics,
+ sbHeightPortrait,
+ roundedCornerPadding)
+
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+
+ // Phone in portrait, seascape (rot_270) bounds
+ targetRotation = ROTATION_SEASCAPE
+ expectedBounds = Rect(roundedCornerPadding,
+ 0,
+ screenBounds.height() - dcBounds.height(),
+ sbHeightLandscape)
+
+ bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ dc,
+ windowMetrics,
+ sbHeightLandscape,
+ roundedCornerPadding)
+
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+ }
+
+ @Test
+ fun testCalculateInsetsForRotationWithRotatedResources_nonCornerCutout() {
+ // GIVEN phone in portrait mode, where width < height and the cutout is not in the corner
+ // the assumption here is that if the cutout does NOT touch the corner then we have room to
+ // layout the status bar in the given space.
+
+ val screenBounds = Rect(0, 0, 1080, 2160)
+ // cutout centered at the top
+ val dcBounds = Rect(490, 0, 590, 100)
+ val roundedCornerPadding = 20
+ val sbHeightPortrait = 100
+ val sbHeightLandscape = 60
+ val currentRotation = ROTATION_NONE
+
+ `when`(windowMetrics.bounds).thenReturn(screenBounds)
+ `when`(dc.boundingRects).thenReturn(listOf(dcBounds))
+
+ // THEN only the landscape/seascape rotations should avoid the cutout area because of the
+ // potential letterboxing
+ var targetRotation = ROTATION_NONE
+ var expectedBounds = Rect(roundedCornerPadding,
+ 0,
+ screenBounds.right - roundedCornerPadding,
+ sbHeightPortrait)
+
+ var bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ dc,
+ windowMetrics,
+ sbHeightPortrait,
+ roundedCornerPadding)
+
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+
+ targetRotation = ROTATION_LANDSCAPE
+ expectedBounds = Rect(dcBounds.height(),
+ 0,
+ screenBounds.height() - roundedCornerPadding,
+ sbHeightLandscape)
+
+ bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ dc,
+ windowMetrics,
+ sbHeightLandscape,
+ roundedCornerPadding)
+
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+
+ targetRotation = ROTATION_UPSIDE_DOWN
+ expectedBounds = Rect(roundedCornerPadding,
+ 0,
+ screenBounds.right - roundedCornerPadding,
+ sbHeightPortrait)
+
+ bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ dc,
+ windowMetrics,
+ sbHeightPortrait,
+ roundedCornerPadding)
+
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+
+ targetRotation = ROTATION_SEASCAPE
+ expectedBounds = Rect(roundedCornerPadding,
+ 0,
+ screenBounds.height() - dcBounds.height(),
+ sbHeightLandscape)
+
+ bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ dc,
+ windowMetrics,
+ sbHeightLandscape,
+ roundedCornerPadding)
+
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+ }
+
+ @Test
+ fun testCalculateInsetsForRotationWithRotatedResources_noCutout() {
+ // GIVEN device in portrait mode, where width < height and no cutout
+ val currentRotation = ROTATION_NONE
+ val screenBounds = Rect(0, 0, 1080, 2160)
+ val roundedCornerPadding = 20
+ val sbHeightPortrait = 100
+ val sbHeightLandscape = 60
+
+ `when`(windowMetrics.bounds).thenReturn(screenBounds)
+
+ // THEN content insets should only use rounded corner padding
+ var targetRotation = ROTATION_NONE
+ var expectedBounds = Rect(roundedCornerPadding,
+ 0,
+ screenBounds.right - roundedCornerPadding,
+ sbHeightPortrait)
+
+ var bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ null, /* no cutout */
+ windowMetrics,
+ sbHeightPortrait,
+ roundedCornerPadding)
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+
+ targetRotation = ROTATION_LANDSCAPE
+ expectedBounds = Rect(roundedCornerPadding,
+ 0,
+ screenBounds.height() - roundedCornerPadding,
+ sbHeightLandscape)
+
+ bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ null, /* no cutout */
+ windowMetrics,
+ sbHeightLandscape,
+ roundedCornerPadding)
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+
+ targetRotation = ROTATION_UPSIDE_DOWN
+ expectedBounds = Rect(roundedCornerPadding,
+ 0,
+ screenBounds.width() - roundedCornerPadding,
+ sbHeightPortrait)
+
+ bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ null, /* no cutout */
+ windowMetrics,
+ sbHeightPortrait,
+ roundedCornerPadding)
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+
+ targetRotation = ROTATION_LANDSCAPE
+ expectedBounds = Rect(roundedCornerPadding,
+ 0,
+ screenBounds.height() - roundedCornerPadding,
+ sbHeightLandscape)
+
+ bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ null, /* no cutout */
+ windowMetrics,
+ sbHeightLandscape,
+ roundedCornerPadding)
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+ }
+
+ private fun assertRects(
+ expected: Rect,
+ actual: Rect,
+ @Rotation currentRotation: Int,
+ @Rotation targetRotation: Int
+ ) {
+ assertTrue(
+ "Rects must match. currentRotation=${RotationUtils.toString(currentRotation)}" +
+ " targetRotation=${RotationUtils.toString(targetRotation)}" +
+ " expected=$expected actual=$actual",
+ expected.equals(actual))
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
index 53a2efc..4b87ec8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
@@ -32,6 +32,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import org.junit.Before;
import org.junit.Test;
@@ -49,12 +50,14 @@
@Mock
private LockPatternUtils mLockPatternUtils;
private KeyguardStateController mKeyguardStateController;
+ @Mock
+ private SmartspaceTransitionController mSmartSpaceTransitionController;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mKeyguardStateController = new KeyguardStateControllerImpl(mContext,
- mKeyguardUpdateMonitor, mLockPatternUtils);
+ mKeyguardUpdateMonitor, mLockPatternUtils, mSmartSpaceTransitionController);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
index 365c62c..9b177e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
@@ -17,7 +17,6 @@
package com.android.systemui.toast;
import static android.view.accessibility.AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
-import static android.widget.ToastPresenter.TEXT_TOAST_LAYOUT;
import static com.google.common.truth.Truth.assertThat;
@@ -31,13 +30,20 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.Application;
import android.app.INotificationManager;
import android.app.ITransientNotificationCallback;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.os.Binder;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.UserHandle;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -47,12 +53,11 @@
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;
-import android.widget.ToastPresenter;
import androidx.test.filters.SmallTest;
-import com.android.internal.R;
import com.android.internal.util.IntPair;
+import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.shared.plugins.PluginManager;
@@ -70,6 +75,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
public class ToastUITest extends SysuiTestCase {
private static final int ANDROID_UID = 1000;
private static final int SYSTEMUI_UID = 10140;
@@ -85,12 +91,14 @@
private static final Binder WINDOW_TOKEN_2 = new Binder();
private static final String TEXT = "Hello World";
- private static final int MESSAGE_RES_ID = R.id.message;
+ private static final int MESSAGE_RES_ID = R.id.text;
private Context mContextSpy;
private ToastUI mToastUI;
- @Mock private LayoutInflater mLayoutInflater;
+ private View mToastView;
+ @Mock private Application mApplication;
@Mock private CommandQueue mCommandQueue;
+ @Mock private LayoutInflater mLayoutInflater;
@Mock private WindowManager mWindowManager;
@Mock private INotificationManager mNotificationManager;
@Mock private IAccessibilityManager mAccessibilityManager;
@@ -98,6 +106,7 @@
@Mock private DumpManager mDumpManager;
@Mock private ToastLogger mToastLogger;
@Mock private FeatureFlags mFeatureFlags;
+ @Mock private PackageManager mPackageManager;
@Mock private ITransientNotificationCallback mCallback;
@Captor private ArgumentCaptor<View> mViewCaptor;
@@ -106,29 +115,33 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- when(mLayoutInflater.inflate(eq(TEXT_TOAST_LAYOUT), any())).thenReturn(
- ToastPresenter.getTextToastView(mContext, TEXT));
- when(mFeatureFlags.isToastStyleEnabled()).thenReturn(false);
-
+ mToastView = LayoutInflater.from(mContext).inflate(R.layout.text_toast, null);
+ when(mLayoutInflater.inflate(anyInt(), eq(null))).thenReturn(mToastView);
mContext.addMockSystemService(WindowManager.class, mWindowManager);
mContextSpy = spy(mContext);
+ when(mContextSpy.getPackageManager()).thenReturn(mPackageManager);
doReturn(mContextSpy).when(mContextSpy).createContextAsUser(any(), anyInt());
-
- doReturn(mContextSpy).when(mContextSpy).createContextAsUser(any(), anyInt());
- mToastUI = new ToastUI(mContextSpy, mCommandQueue, mNotificationManager,
- mAccessibilityManager, new ToastFactory(mLayoutInflater, mPluginManager,
- mDumpManager, mFeatureFlags), mToastLogger);
+ mToastUI = new ToastUI(
+ mContextSpy,
+ mCommandQueue,
+ mNotificationManager,
+ mAccessibilityManager,
+ new ToastFactory(
+ mLayoutInflater,
+ mPluginManager,
+ mDumpManager),
+ mToastLogger);
}
@Test
- public void testStart_addToastUIAsCallbackToCommandQueue() throws Exception {
+ public void testStart_addToastUIAsCallbackToCommandQueue() {
mToastUI.start();
verify(mCommandQueue).addCallback(mToastUI);
}
@Test
- public void testShowToast_addsCorrectViewToWindowManager() throws Exception {
+ public void testShowToast_addsCorrectViewToWindowManager() {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
null);
@@ -138,7 +151,7 @@
}
@Test
- public void testShowToast_addsViewWithCorrectLayoutParamsToWindowManager() throws Exception {
+ public void testShowToast_addsViewWithCorrectLayoutParamsToWindowManager() {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
null);
@@ -217,9 +230,14 @@
public void testHideToast_removesView() throws Exception {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
- View view = verifyWmAddViewAndAttachToParent();
+ final SystemUIToast toast = mToastUI.mToast;
+ View view = verifyWmAddViewAndAttachToParent();
mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
+ if (toast.getOutAnimation() != null) {
+ assertThat(toast.getOutAnimation().isRunning()).isTrue();
+ toast.getOutAnimation().cancel(); // if applicable, try to finish anim early
+ }
verify(mWindowManager).removeViewImmediate(view);
}
@@ -228,51 +246,81 @@
public void testHideToast_finishesToken() throws Exception {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
+ final SystemUIToast toast = mToastUI.mToast;
+ verifyWmAddViewAndAttachToParent();
mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
+ if (toast.getOutAnimation() != null) {
+ assertThat(toast.getOutAnimation().isRunning()).isTrue();
+ toast.getOutAnimation().cancel(); // if applicable, try to finish anim early
+ }
verify(mNotificationManager).finishToken(PACKAGE_NAME_1, TOKEN_1);
}
@Test
- public void testHideToast_callsCallback() throws Exception {
+ public void testHideToast_callsCallback() throws RemoteException {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
+ final SystemUIToast toast = mToastUI.mToast;
+ verifyWmAddViewAndAttachToParent();
mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
+ if (toast.getOutAnimation() != null) {
+ assertThat(toast.getOutAnimation().isRunning()).isTrue();
+ toast.getOutAnimation().cancel();
+ }
verify(mCallback).onToastHidden();
}
@Test
- public void testHideToast_whenNotCurrentToastToken_doesNotHideToast() throws Exception {
+ public void testHideToast_whenNotCurrentToastToken_doesNotHideToast() throws RemoteException {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
+ final SystemUIToast toast = mToastUI.mToast;
+ verifyWmAddViewAndAttachToParent();
mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_2);
+ if (toast.getOutAnimation() != null) {
+ assertThat(toast.getOutAnimation().isRunning()).isFalse();
+ }
+
verify(mCallback, never()).onToastHidden();
}
@Test
- public void testHideToast_whenNotCurrentToastPackage_doesNotHideToast() throws Exception {
+ public void testHideToast_whenNotCurrentToastPackage_doesNotHideToast() throws RemoteException {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
+ final SystemUIToast toast = mToastUI.mToast;
+ verifyWmAddViewAndAttachToParent();
mToastUI.hideToast(PACKAGE_NAME_2, TOKEN_1);
+ if (toast.getOutAnimation() != null) {
+ assertThat(toast.getOutAnimation().isRunning()).isFalse();
+ }
+
verify(mCallback, never()).onToastHidden();
}
@Test
- public void testShowToast_afterShowToast_hidesCurrentToast() throws Exception {
+ public void testShowToast_afterShowToast_hidesCurrentToast() throws RemoteException {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
- View view = verifyWmAddViewAndAttachToParent();
+ final SystemUIToast toast = mToastUI.mToast;
+ View view = verifyWmAddViewAndAttachToParent();
mToastUI.showToast(UID_2, PACKAGE_NAME_2, TOKEN_2, TEXT, WINDOW_TOKEN_2, Toast.LENGTH_LONG,
null);
+ if (toast.getOutAnimation() != null) {
+ assertThat(toast.getOutAnimation().isRunning()).isTrue();
+ toast.getOutAnimation().cancel(); // end early if applicable
+ }
+
verify(mWindowManager).removeViewImmediate(view);
verify(mNotificationManager).finishToken(PACKAGE_NAME_1, TOKEN_1);
verify(mCallback).onToastHidden();
@@ -287,9 +335,48 @@
}
@Test
+ public void testShowToast_targetsPreS_unlimitedLines_noAppIcon()
+ throws PackageManager.NameNotFoundException {
+ // GIVEN the application targets R
+ ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.targetSdkVersion = Build.VERSION_CODES.R;
+ when(mPackageManager.getApplicationInfoAsUser(PACKAGE_NAME_1, 0,
+ UserHandle.getUserHandleForUid(UID_1).getIdentifier())).thenReturn(applicationInfo);
+
+ // WHEN the package posts a toast
+ mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+ mCallback);
+
+ // THEN the view can have unlimited lines
+ assertThat(((TextView) mToastUI.mToast.getView()
+ .findViewById(com.android.systemui.R.id.text))
+ .getMaxLines()).isEqualTo(Integer.MAX_VALUE);
+ }
+
+ @Test
+ public void testShowToast_targetsS_twoLineLimit_noAppIcon()
+ throws PackageManager.NameNotFoundException {
+ // GIVEN the application targets S
+ ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.targetSdkVersion = Build.VERSION_CODES.S;
+ when(mPackageManager.getApplicationInfoAsUser(PACKAGE_NAME_1, 0,
+ UserHandle.getUserHandleForUid(UID_1).getIdentifier())).thenReturn(applicationInfo);
+
+ // WHEN the package posts a toast
+ mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+ mCallback);
+
+ // THEN the view is limited to 2 lines
+ assertThat(((TextView) mToastUI.mToast.getView()
+ .findViewById(com.android.systemui.R.id.text))
+ .getMaxLines()).isEqualTo(2);
+ }
+
+ @Test
public void testHideToast_logs() {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
+ verifyWmAddViewAndAttachToParent();
mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
verify(mToastLogger).logOnHideToast(PACKAGE_NAME_1, TOKEN_1.toString());
}
@@ -298,6 +385,7 @@
public void testHideToast_error_noLog() {
// no toast was shown, so this hide is invalid
mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
+ assertThat(mToastUI.mToast).isNull();
verify(mToastLogger, never()).logOnHideToast(PACKAGE_NAME_1, TOKEN_1.toString());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeThreadFactory.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeThreadFactory.java
index 570e1d8..301a157 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeThreadFactory.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeThreadFactory.java
@@ -27,6 +27,7 @@
public class FakeThreadFactory implements ThreadFactory {
private final FakeExecutor mFakeExecutor;
private Handler mHandler;
+ private Looper mLooper;
public FakeThreadFactory(FakeExecutor fakeExecutor) {
mFakeExecutor = fakeExecutor;
@@ -36,8 +37,17 @@
mHandler = handler;
}
+ public void setLooper(Looper looper) {
+ mLooper = looper;
+ }
+
@Override
- public Handler builderHandlerOnNewThread(String threadName) {
+ public Looper buildLooperOnNewThread(String threadName) {
+ return mLooper;
+ }
+
+ @Override
+ public Handler buildHandlerOnNewThread(String threadName) {
return mHandler;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java
index 5fb779a..1aebf1c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java
@@ -127,4 +127,9 @@
public void notifyPanelFlingEnd() {
}
+
+ @Override
+ public boolean canPerformSmartSpaceTransition() {
+ return false;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
index 6166cd7..5c0efd3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
@@ -23,29 +23,37 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.media.AudioManager;
+import android.media.IAudioService;
import android.media.session.MediaSession;
import android.os.Handler;
import android.os.Process;
+import android.os.Vibrator;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.view.accessibility.AccessibilityManager;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.keyguard.WakefulnessLifecycle;
-import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.util.RingerModeLiveData;
import com.android.systemui.util.RingerModeTracker;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.concurrency.FakeThreadFactory;
+import com.android.systemui.util.concurrency.ThreadFactory;
+import com.android.systemui.util.time.FakeSystemClock;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -58,7 +66,6 @@
TestableVolumeDialogControllerImpl mVolumeController;
VolumeDialogControllerImpl.C mCallback;
- StatusBar mStatusBar;
@Mock
private BroadcastDispatcher mBroadcastDispatcher;
@Mock
@@ -67,6 +74,23 @@
private RingerModeLiveData mRingerModeLiveData;
@Mock
private RingerModeLiveData mRingerModeInternalLiveData;
+ private final FakeThreadFactory mThreadFactory = new FakeThreadFactory(
+ new FakeExecutor(new FakeSystemClock()));
+ @Mock
+ private AudioManager mAudioManager;
+ @Mock
+ private NotificationManager mNotificationManager;
+ @Mock
+ private Vibrator mVibrator;
+ @Mock
+ private IAudioService mIAudioService;
+ @Mock
+ private AccessibilityManager mAccessibilityManager;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private WakefulnessLifecycle mWakefullnessLifcycle;
+
@Before
public void setup() throws Exception {
@@ -77,19 +101,15 @@
// Initial non-set value
when(mRingerModeLiveData.getValue()).thenReturn(-1);
when(mRingerModeInternalLiveData.getValue()).thenReturn(-1);
-
mCallback = mock(VolumeDialogControllerImpl.C.class);
- mStatusBar = mock(StatusBar.class);
- mVolumeController = new TestableVolumeDialogControllerImpl(mContext, mCallback, mStatusBar,
- mBroadcastDispatcher, mRingerModeTracker);
+ mThreadFactory.setLooper(TestableLooper.get(this).getLooper());
+ mVolumeController = new TestableVolumeDialogControllerImpl(mContext,
+ mBroadcastDispatcher, mRingerModeTracker, mThreadFactory, mAudioManager,
+ mNotificationManager, Optional.of(mVibrator), mIAudioService, mAccessibilityManager,
+ mPackageManager, mWakefullnessLifcycle, mCallback);
mVolumeController.setEnableDialogs(true, true);
}
- @After
- public void tearDown() {
- mVolumeController.destroy();
- }
-
@Test
public void testRegisteredWithDispatcher() {
verify(mBroadcastDispatcher).registerReceiverWithHandler(any(BroadcastReceiver.class),
@@ -99,45 +119,36 @@
@Test
public void testVolumeChangeW_deviceNotInteractiveAOD() {
- when(mStatusBar.isDeviceInteractive()).thenReturn(false);
- when(mStatusBar.getWakefulnessState()).thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE);
+ mVolumeController.setDeviceInteractive(false);
+ when(mWakefullnessLifcycle.getWakefulness()).thenReturn(
+ WakefulnessLifecycle.WAKEFULNESS_AWAKE);
mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
verify(mCallback, never()).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
}
@Test
public void testVolumeChangeW_deviceInteractive() {
- when(mStatusBar.isDeviceInteractive()).thenReturn(true);
- when(mStatusBar.getWakefulnessState()).thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE);
+ mVolumeController.setDeviceInteractive(true);
+ when(mWakefullnessLifcycle.getWakefulness()).thenReturn(
+ WakefulnessLifecycle.WAKEFULNESS_AWAKE);
mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
verify(mCallback, times(1)).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
}
@Test
public void testVolumeChangeW_deviceInteractive_StartedSleeping() {
- when(mStatusBar.isDeviceInteractive()).thenReturn(true);
- when(mStatusBar.getWakefulnessState()).thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE);
+ mVolumeController.setDeviceInteractive(true);
+ when(mWakefullnessLifcycle.getWakefulness()).thenReturn(
+ WakefulnessLifecycle.WAKEFULNESS_AWAKE);
mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
- when(mStatusBar.isDeviceInteractive()).thenReturn(false);
- when(mStatusBar.getWakefulnessState()).thenReturn(
+ mVolumeController.setDeviceInteractive(false);
+ when(mWakefullnessLifcycle.getWakefulness()).thenReturn(
WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP);
mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
verify(mCallback, times(1)).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
}
@Test
- public void testVolumeChangeW_nullStatusBar() {
- VolumeDialogControllerImpl.C callback = mock(VolumeDialogControllerImpl.C.class);
- TestableVolumeDialogControllerImpl
- nullStatusBarTestableDialog =
- new TestableVolumeDialogControllerImpl(
- mContext, callback, null, mBroadcastDispatcher, mRingerModeTracker);
- nullStatusBarTestableDialog.setEnableDialogs(true, true);
- nullStatusBarTestableDialog.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
- verify(callback, times(1)).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
- }
-
- @Test
public void testOnRemoteVolumeChanged_newStream_noNullPointer() {
MediaSession.Token token = new MediaSession.Token(Process.myUid(), null);
mVolumeController.mMediaSessionsCallbacksW.onRemoteVolumeChanged(token, 0);
@@ -155,22 +166,51 @@
verify(mRingerModeInternalLiveData).observeForever(any());
}
- @Test
- public void testRingerModeOnDestroy_observersRemoved() {
- mVolumeController.destroy();
-
- verify(mRingerModeLiveData).removeObserver(any());
- verify(mRingerModeInternalLiveData).removeObserver(any());
- }
-
static class TestableVolumeDialogControllerImpl extends VolumeDialogControllerImpl {
- TestableVolumeDialogControllerImpl(Context context, C callback, StatusBar s,
- BroadcastDispatcher broadcastDispatcher, RingerModeTracker ringerModeTracker) {
- super(
- context, broadcastDispatcher,
- s == null ? Optional.empty() : Optional.of(() -> s), ringerModeTracker);
+ private final WakefulnessLifecycle.Observer mWakefullessLifecycleObserver;
+
+ TestableVolumeDialogControllerImpl(
+ Context context,
+ BroadcastDispatcher broadcastDispatcher,
+ RingerModeTracker ringerModeTracker,
+ ThreadFactory theadFactory,
+ AudioManager audioManager,
+ NotificationManager notificationManager,
+ Optional<Vibrator> optionalVibrator,
+ IAudioService iAudioService,
+ AccessibilityManager accessibilityManager,
+ PackageManager packageManager,
+ WakefulnessLifecycle wakefulnessLifecycle,
+ C callback) {
+ super(context, broadcastDispatcher, ringerModeTracker, theadFactory, audioManager,
+ notificationManager, optionalVibrator, iAudioService, accessibilityManager,
+ packageManager, wakefulnessLifecycle);
mCallbacks = callback;
+
+ ArgumentCaptor<WakefulnessLifecycle.Observer> observerCaptor =
+ ArgumentCaptor.forClass(WakefulnessLifecycle.Observer.class);
+ verify(wakefulnessLifecycle).addObserver(observerCaptor.capture());
+ mWakefullessLifecycleObserver = observerCaptor.getValue();
+ }
+
+ public void setDeviceInteractive(boolean interactive) {
+ if (interactive) {
+ mWakefullessLifecycleObserver.onStartedWakingUp();
+ } else {
+ mWakefullessLifecycleObserver.onFinishedGoingToSleep();
+ }
}
}
+// static class TestableVolumeDialogControllerImpl extends VolumeDialogControllerImpl {
+// TestableVolumeDialogControllerImpl(Context context, C callback,
+// BroadcastDispatcher broadcastDispatcher, RingerModeTracker ringerModeTracker,
+// ThreadFactory threadFactory) {
+// super(
+// context, broadcastDispatcher,
+// s == null ? Optional.empty() : Optional.of(() -> s), ringerModeTracker);
+// mCallbacks = callback;
+// }
+// }
+
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
new file mode 100644
index 0000000..33666bc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wallet.controller;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.service.quickaccesswallet.GetWalletCardsRequest;
+import android.service.quickaccesswallet.QuickAccessWalletClient;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.settings.SecureSettings;
+
+import com.google.common.util.concurrent.MoreExecutors;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class QuickAccessWalletControllerTest extends SysuiTestCase {
+
+ @Mock
+ private QuickAccessWalletClient mQuickAccessWalletClient;
+ @Mock
+ private SecureSettings mSecureSettings;
+ @Mock
+ private QuickAccessWalletClient.OnWalletCardsRetrievedCallback mCardsRetriever;
+ @Captor
+ private ArgumentCaptor<GetWalletCardsRequest> mRequestCaptor;
+
+ private QuickAccessWalletController mController;
+ private TestableLooper mTestableLooper;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mTestableLooper = TestableLooper.get(this);
+ when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(true);
+ when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(true);
+ when(mQuickAccessWalletClient.isWalletFeatureAvailableWhenDeviceLocked()).thenReturn(true);
+
+ mController = new QuickAccessWalletController(
+ mContext,
+ MoreExecutors.directExecutor(),
+ mSecureSettings,
+ mQuickAccessWalletClient);
+ }
+
+ @Test
+ public void walletEnabled() {
+ mController.updateWalletPreference();
+
+ assertTrue(mController.isWalletEnabled());
+ }
+
+ @Test
+ public void walletServiceUnavailable_walletNotEnabled() {
+ when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(false);
+
+ mController.updateWalletPreference();
+
+ assertFalse(mController.isWalletEnabled());
+ }
+
+ @Test
+ public void walletFeatureUnavailable_walletNotEnabled() {
+ when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(false);
+
+ mController.updateWalletPreference();
+
+ assertFalse(mController.isWalletEnabled());
+ }
+
+ @Test
+ public void walletFeatureWhenLockedUnavailable_walletNotEnabled() {
+ when(mQuickAccessWalletClient.isWalletFeatureAvailableWhenDeviceLocked()).thenReturn(false);
+
+ mController.updateWalletPreference();
+
+ assertFalse(mController.isWalletEnabled());
+ }
+
+ @Test
+ public void getWalletClient_NoRecreation_sameClient() {
+ assertSame(mQuickAccessWalletClient, mController.getWalletClient());
+ }
+
+ @Test
+ public void getWalletClient_reCreateClient_notSameClient() {
+ mController.reCreateWalletClient();
+
+ assertNotSame(mQuickAccessWalletClient, mController.getWalletClient());
+ }
+
+ @Test
+ public void queryWalletCards_walletNotEnabled_notQuery() {
+ when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(false);
+
+ mController.queryWalletCards(mCardsRetriever);
+
+ verify(mQuickAccessWalletClient, never()).getWalletCards(any(), any(), any());
+ }
+
+ @Test
+ public void queryWalletCards_walletEnabled_queryCards() {
+ mController.updateWalletPreference();
+ mController.queryWalletCards(mCardsRetriever);
+
+ verify(mQuickAccessWalletClient)
+ .getWalletCards(
+ eq(MoreExecutors.directExecutor()),
+ mRequestCaptor.capture(),
+ eq(mCardsRetriever));
+
+ GetWalletCardsRequest request = mRequestCaptor.getValue();
+ assertEquals(1, mRequestCaptor.getValue().getMaxCards());
+ assertEquals(
+ mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_width),
+ request.getCardWidthPx());
+ assertEquals(
+ mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_height),
+ request.getCardHeightPx());
+ }
+}
diff --git a/services/Android.bp b/services/Android.bp
index f2e0b20..c83a697 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -72,17 +72,6 @@
visibility: ["//visibility:private"],
}
-filegroup {
- name: "services-all-sources",
- srcs: [
- ":services-non-updatable-sources",
- ":service-media-s-sources",
- ":service-permission-sources",
- ":service-statsd-sources",
- ],
- visibility: ["//visibility:private"],
-}
-
java_library {
name: "Slogf",
srcs: ["core/java/com/android/server/utils/Slogf.java"],
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 0408309..71d6a48 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2569,10 +2569,6 @@
s.setAllowedBgActivityStartsByBinding(true);
}
- if ((flags & Context.BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND) != 0) {
- s.setAllowedBgFgsStartsByBinding(true);
- }
-
if ((flags & Context.BIND_NOT_APP_COMPONENT_USAGE) != 0) {
s.isNotAppComponentUsage = true;
}
@@ -4129,9 +4125,6 @@
if ((c.flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
s.updateIsAllowedBgActivityStartsByBinding();
}
- if ((c.flags & Context.BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND) != 0) {
- s.updateIsAllowedBgFgsStartsByBinding();
- }
if (s.app != null) {
updateServiceClientActivitiesLocked(s.app.mServices, c, true);
}
@@ -5856,8 +5849,6 @@
final ProcessStateRecord state = app.mState;
if (state.isAllowedStartFgsState()) {
return getReasonCodeFromProcState(state.getAllowStartFgsState());
- } else if (state.areBackgroundFgsStartsAllowedByToken()) {
- return REASON_FGS_BINDING;
} else {
final ActiveInstrumentation instr = app.getActiveInstrumentation();
if (instr != null
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 88f4fc2..3e6a0a8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1236,7 +1236,7 @@
* The temp-allowlist that is allowed to start FGS from background.
*/
@CompositeRWLock({"this", "mProcLock"})
- final FgsTempAllowList<Integer, FgsTempAllowListItem> mFgsStartTempAllowList =
+ final FgsTempAllowList<FgsTempAllowListItem> mFgsStartTempAllowList =
new FgsTempAllowList();
static final FgsTempAllowListItem FAKE_TEMP_ALLOW_LIST_ITEM = new FgsTempAllowListItem(
@@ -1246,7 +1246,7 @@
* List of uids that are allowed to have while-in-use permission when FGS is started from
* background.
*/
- private final FgsTempAllowList<Integer, String> mFgsWhileInUseTempAllowList =
+ private final FgsTempAllowList<String> mFgsWhileInUseTempAllowList =
new FgsTempAllowList();
/**
@@ -2589,6 +2589,7 @@
addServiceToMap(mAppBindArgs, Context.POWER_SERVICE);
addServiceToMap(mAppBindArgs, Context.USER_SERVICE);
addServiceToMap(mAppBindArgs, "mount");
+ addServiceToMap(mAppBindArgs, Context.PLATFORM_COMPAT_SERVICE);
}
return mAppBindArgs;
}
@@ -9371,22 +9372,17 @@
pw.println(" mFgsStartTempAllowList:");
final long currentTimeNow = System.currentTimeMillis();
final long elapsedRealtimeNow = SystemClock.elapsedRealtime();
- final Set<Integer> uids = new ArraySet<>(mFgsStartTempAllowList.keySet());
- for (Integer uid : uids) {
- final Pair<Long, FgsTempAllowListItem> entry = mFgsStartTempAllowList.get(uid);
- if (entry == null) {
- continue;
- }
+ mFgsStartTempAllowList.forEach((uid, entry) -> {
pw.print(" " + UserHandle.formatUid(uid) + ": ");
- entry.second.dump(pw); pw.println();
- pw.print("ms expiration=");
+ entry.second.dump(pw);
+ pw.print(" expiration=");
// Convert entry.mExpirationTime, which is an elapsed time since boot,
// to a time since epoch (i.e. System.currentTimeMillis()-based time.)
final long expirationInCurrentTime =
currentTimeNow - elapsedRealtimeNow + entry.first;
TimeUtils.dumpTimeWithDelta(pw, expirationInCurrentTime, currentTimeNow);
pw.println();
- }
+ });
}
if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
|| mOrigWaitForDebugger) {
@@ -15344,10 +15340,19 @@
mDeviceIdleTempAllowlist = appids;
if (adding) {
if (type == TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
+ // Note, the device idle temp-allowlist are by app-ids, but here
+ // mFgsStartTempAllowList contains UIDs.
mFgsStartTempAllowList.add(changingUid, durationMs,
new FgsTempAllowListItem(durationMs, reasonCode, reason,
callingUid));
}
+ } else {
+ // Note in the removing case, we need to remove all the UIDs matching
+ // the appId, because DeviceIdle's temp-allowlist are based on AppIds,
+ // not UIDs.
+ // For eacmple, "cmd deviceidle tempallowlist -r PACKAGE" will
+ // not only remove this app for user 0, but for all users.
+ mFgsStartTempAllowList.removeAppId(UserHandle.getAppId(changingUid));
}
setAppIdTempAllowlistStateLSP(changingUid, adding);
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 6cb374a..4e6e91a 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -771,9 +771,7 @@
default:
throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
}
- // TODO(b/187223764): busTime won't be needed once end_session is a field in BUS.
- final long busTime = System.currentTimeMillis();
- final byte[] statsProto = bus.getStatsProto(busTime);
+ final byte[] statsProto = bus.getStatsProto();
data.add(FrameworkStatsLog.buildStatsEvent(atomTag, statsProto));
diff --git a/services/core/java/com/android/server/am/FgsTempAllowList.java b/services/core/java/com/android/server/am/FgsTempAllowList.java
index 847e82f..c286556 100644
--- a/services/core/java/com/android/server/am/FgsTempAllowList.java
+++ b/services/core/java/com/android/server/am/FgsTempAllowList.java
@@ -20,11 +20,12 @@
import android.annotation.Nullable;
import android.os.SystemClock;
-import android.util.ArrayMap;
+import android.os.UserHandle;
import android.util.Pair;
import android.util.Slog;
+import android.util.SparseArray;
-import java.util.Set;
+import java.util.function.BiConsumer;
/**
* List of keys that have expiration time.
@@ -33,19 +34,18 @@
*
* <p>This is used for both FGS-BG-start restriction, and FGS-while-in-use permissions check.</p>
*
- * <p>Note: the underlying data structure is an {@link ArrayMap}, for performance reason, it is only
- * suitable to hold up to hundreds of entries.</p>
- * @param <K> type of the key.
+ * <p>Note: the underlying data structure is an {@link SparseArray}, for performance reason,
+ * it is only suitable to hold up to hundreds of entries.</p>
* @param <E> type of the additional optional info.
*/
-public class FgsTempAllowList<K, E> {
+public class FgsTempAllowList<E> {
private static final int DEFAULT_MAX_SIZE = 100;
/**
* The value is Pair type, Pair.first is the expirationTime(an elapsedRealtime),
* Pair.second is the optional information entry about this key.
*/
- private final ArrayMap<K, Pair<Long, E>> mTempAllowList = new ArrayMap<>();
+ private final SparseArray<Pair<Long, E>> mTempAllowList = new SparseArray<>();
private int mMaxSize = DEFAULT_MAX_SIZE;
private final Object mLock = new Object();
@@ -70,15 +70,14 @@
/**
* Add a key and its duration with optional info into the temp allowlist.
- * @param key
* @param durationMs temp-allowlisted duration in milliseconds.
* @param entry additional optional information of this key, could be null.
*/
- public void add(K key, long durationMs, @Nullable E entry) {
+ public void add(int uid, long durationMs, @Nullable E entry) {
synchronized (mLock) {
if (durationMs <= 0) {
Slog.e(TAG_AM, "FgsTempAllowList bad duration:" + durationMs + " key: "
- + key);
+ + uid);
return;
}
// The temp allowlist should be a short list with only a few entries in it.
@@ -94,10 +93,10 @@
}
}
}
- final Pair<Long, E> existing = mTempAllowList.get(key);
+ final Pair<Long, E> existing = mTempAllowList.get(uid);
final long expirationTime = now + durationMs;
if (existing == null || existing.first < expirationTime) {
- mTempAllowList.put(key, new Pair(expirationTime, entry));
+ mTempAllowList.put(uid, new Pair(expirationTime, entry));
}
}
}
@@ -105,13 +104,12 @@
/**
* If the key has not expired (AKA allowed), return its non-null value.
* If the key has expired, return null.
- * @param key
* @return
*/
@Nullable
- public Pair<Long, E> get(K key) {
+ public Pair<Long, E> get(int uid) {
synchronized (mLock) {
- final int index = mTempAllowList.indexOfKey(key);
+ final int index = mTempAllowList.indexOfKey(uid);
if (index < 0) {
return null;
} else if (mTempAllowList.valueAt(index).first < SystemClock.elapsedRealtime()) {
@@ -126,23 +124,48 @@
/**
* If the key has not expired (AKA allowed), return true.
* If the key has expired, return false.
- * @param key
- * @return
*/
- public boolean isAllowed(K key) {
- Pair<Long, E> entry = get(key);
+ public boolean isAllowed(int uid) {
+ Pair<Long, E> entry = get(uid);
return entry != null;
}
- public void remove(K key) {
+ /**
+ * Remove a given UID.
+ */
+ public void removeUid(int uid) {
synchronized (mLock) {
- mTempAllowList.remove(key);
+ mTempAllowList.remove(uid);
}
}
- public Set<K> keySet() {
+ /**
+ * Remove by appId.
+ */
+ public void removeAppId(int appId) {
synchronized (mLock) {
- return mTempAllowList.keySet();
+ // Find all UIDs matching the appId.
+ for (int i = mTempAllowList.size() - 1; i >= 0; i--) {
+ final int uid = mTempAllowList.keyAt(i);
+ if (UserHandle.getAppId(uid) == appId) {
+ mTempAllowList.removeAt(i);
+ }
+ }
+ }
+ }
+
+ /**
+ * Iterate over the entries.
+ */
+ public void forEach(BiConsumer<Integer, Pair<Long, E>> callback) {
+ synchronized (mLock) {
+ for (int i = 0; i < mTempAllowList.size(); i++) {
+ final int uid = mTempAllowList.keyAt(i);
+ final Pair<Long, E> entry = mTempAllowList.valueAt(i);
+ if (entry != null) {
+ callback.accept(uid, entry);
+ }
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 0ffaccf..457fe0f 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -3074,7 +3074,7 @@
UidRecord.CHANGE_GONE);
EventLogTags.writeAmUidStopped(uid);
mActiveUids.remove(uid);
- mService.mFgsStartTempAllowList.remove(record.info.uid);
+ mService.mFgsStartTempAllowList.removeUid(record.info.uid);
mService.noteUidProcessState(uid, ActivityManager.PROCESS_STATE_NONEXISTENT,
ActivityManager.PROCESS_CAPABILITY_NONE);
}
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index d83e13c..1fb5572 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -26,7 +26,6 @@
import android.annotation.ElapsedRealtimeLong;
import android.app.ActivityManager;
import android.content.ComponentName;
-import android.os.Binder;
import android.os.SystemClock;
import android.util.ArraySet;
import android.util.Slog;
@@ -302,9 +301,6 @@
@GuardedBy("mService")
private int mAllowStartFgsState = PROCESS_STATE_NONEXISTENT;
- @GuardedBy("mService")
- private final ArraySet<Binder> mBackgroundFgsStartTokens = new ArraySet<>();
-
/**
* Whether or not this process has been in forced-app-standby state.
*/
@@ -1101,21 +1097,6 @@
}
@GuardedBy("mService")
- void addAllowBackgroundFgsStartsToken(Binder entity) {
- mBackgroundFgsStartTokens.add(entity);
- }
-
- @GuardedBy("mService")
- void removeAllowBackgroundFgsStartsToken(Binder entity) {
- mBackgroundFgsStartTokens.remove(entity);
- }
-
- @GuardedBy("mService")
- boolean areBackgroundFgsStartsAllowedByToken() {
- return !mBackgroundFgsStartTokens.isEmpty();
- }
-
- @GuardedBy("mService")
void resetAllowStartFgsState() {
mAllowStartFgsState = PROCESS_STATE_NONEXISTENT;
}
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index fd59e85..dbb2f65 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -149,10 +149,6 @@
@GuardedBy("ams")
private List<IBinder> mBgActivityStartsByStartOriginatingTokens = new ArrayList<>();
- // any current binding to this service has BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND
- // flag? if true, the process can start FGS from background.
- boolean mIsAllowedBgFgsStartsByBinding;
-
// allow while-in-use permissions in foreground service or not.
// while-in-use permissions in FGS started from background might be restricted.
boolean mAllowWhileInUsePermissionInFgs;
@@ -445,10 +441,6 @@
pw.print(prefix); pw.print("mIsAllowedBgActivityStartsByStart=");
pw.println(mIsAllowedBgActivityStartsByStart);
}
- if (mIsAllowedBgFgsStartsByBinding) {
- pw.print(prefix); pw.print("mIsAllowedBgFgsStartsByBinding=");
- pw.println(mIsAllowedBgFgsStartsByBinding);
- }
pw.print(prefix); pw.print("allowWhileInUsePermissionInFgs=");
pw.println(mAllowWhileInUsePermissionInFgs);
pw.print(prefix); pw.print("recentCallingPackage=");
@@ -634,11 +626,6 @@
} else {
proc.removeAllowBackgroundActivityStartsToken(this);
}
- if (mIsAllowedBgFgsStartsByBinding) {
- proc.mState.addAllowBackgroundFgsStartsToken(this);
- } else {
- proc.mState.removeAllowBackgroundFgsStartsToken(this);
- }
}
if (app != null && app != proc) {
// If the old app is allowed to start bg activities because of a service start, leave it
@@ -726,34 +713,11 @@
setAllowedBgActivityStartsByBinding(isAllowedByBinding);
}
- void updateIsAllowedBgFgsStartsByBinding() {
- boolean isAllowedByBinding = false;
- for (int conni = connections.size() - 1; conni >= 0; conni--) {
- ArrayList<ConnectionRecord> cr = connections.valueAt(conni);
- for (int i = 0; i < cr.size(); i++) {
- if ((cr.get(i).flags
- & Context.BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND) != 0) {
- isAllowedByBinding = true;
- break;
- }
- }
- if (isAllowedByBinding) {
- break;
- }
- }
- setAllowedBgFgsStartsByBinding(isAllowedByBinding);
- }
-
void setAllowedBgActivityStartsByBinding(boolean newValue) {
mIsAllowedBgActivityStartsByBinding = newValue;
updateParentProcessBgActivityStartsToken();
}
- void setAllowedBgFgsStartsByBinding(boolean newValue) {
- mIsAllowedBgFgsStartsByBinding = newValue;
- updateParentProcessBgFgsStartsToken();
- }
-
/**
* Called when the service is started with allowBackgroundActivityStarts set. We allow
* it for background activity starts, setting up a callback to remove this ability after a
@@ -846,17 +810,6 @@
}
}
- private void updateParentProcessBgFgsStartsToken() {
- if (app == null) {
- return;
- }
- if (mIsAllowedBgFgsStartsByBinding) {
- app.mState.addAllowBackgroundFgsStartsToken(this);
- } else {
- app.mState.removeAllowBackgroundFgsStartsToken(this);
- }
- }
-
/**
* Returns the originating token if that's the only reason background activity starts are
* allowed. In order for that to happen the service has to be allowed only due to starts, since
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 3f2b8ff..b714c6d 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -33,6 +33,9 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
import android.os.Handler;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -126,6 +129,7 @@
ERROR_UNLOCK_ALL_USERS,
ERROR_PROVIDER_MISMATCH,
ERROR_KEYSTORE_FAILURE,
+ ERROR_NO_NETWORK,
})
@Retention(RetentionPolicy.SOURCE)
@interface RebootEscrowErrorCode {
@@ -139,6 +143,7 @@
static final int ERROR_UNLOCK_ALL_USERS = 5;
static final int ERROR_PROVIDER_MISMATCH = 6;
static final int ERROR_KEYSTORE_FAILURE = 7;
+ static final int ERROR_NO_NETWORK = 8;
private @RebootEscrowErrorCode int mLoadEscrowDataErrorCode = ERROR_NONE;
@@ -235,6 +240,23 @@
"server_based_ror_enabled", false);
}
+ public boolean isNetworkConnected() {
+ final ConnectivityManager connectivityManager =
+ mContext.getSystemService(ConnectivityManager.class);
+ if (connectivityManager == null) {
+ return false;
+ }
+
+ Network activeNetwork = connectivityManager.getActiveNetwork();
+ NetworkCapabilities networkCapabilities =
+ connectivityManager.getNetworkCapabilities(activeNetwork);
+ return networkCapabilities != null
+ && networkCapabilities.hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ && networkCapabilities.hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_VALIDATED);
+ }
+
public Context getContext() {
return mContext;
}
@@ -363,7 +385,11 @@
}
Slog.w(TAG, "Failed to load reboot escrow data after " + attemptNumber + " attempts");
- mLoadEscrowDataErrorCode = ERROR_RETRY_COUNT_EXHAUSTED;
+ if (mInjector.serverBasedResumeOnReboot() && !mInjector.isNetworkConnected()) {
+ mLoadEscrowDataErrorCode = ERROR_NO_NETWORK;
+ } else {
+ mLoadEscrowDataErrorCode = ERROR_RETRY_COUNT_EXHAUSTED;
+ }
onGetRebootEscrowKeyFailed(users, attemptNumber);
}
@@ -471,6 +497,8 @@
mLoadEscrowDataErrorCode = ERROR_UNKNOWN;
}
+ Slog.i(TAG, "Reporting RoR recovery metrics, success: " + success + ", service type: "
+ + serviceType + ", error code: " + mLoadEscrowDataErrorCode);
// TODO(179105110) report the duration since boot complete.
mInjector.reportMetric(success, mLoadEscrowDataErrorCode, serviceType, attemptCount,
escrowDurationInSeconds, vbmetaDigestStatus, -1);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 983b5b1..9c25159 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -192,6 +192,7 @@
import com.android.internal.R;
import com.android.internal.accessibility.AccessibilityShortcutController;
+import com.android.internal.app.AssistUtils;
import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
@@ -650,7 +651,8 @@
case MSG_LAUNCH_ASSIST:
final int deviceId = msg.arg1;
final Long eventTime = (Long) msg.obj;
- launchAssistAction(null /* hint */, deviceId, eventTime);
+ launchAssistAction(null /* hint */, deviceId, eventTime,
+ AssistUtils.INVOCATION_TYPE_UNKNOWN);
break;
case MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK:
launchVoiceAssistWithWakeLock();
@@ -1108,7 +1110,8 @@
performHapticFeedback(HapticFeedbackConstants.ASSISTANT_BUTTON, false,
"Power - Long Press - Go To Assistant");
final int powerKeyDeviceId = Integer.MIN_VALUE;
- launchAssistAction(null, powerKeyDeviceId, eventTime);
+ launchAssistAction(null, powerKeyDeviceId, eventTime,
+ AssistUtils.INVOCATION_TYPE_POWER_BUTTON_LONG_PRESS);
break;
}
}
@@ -1541,7 +1544,8 @@
launchAllAppsAction();
break;
case LONG_PRESS_HOME_ASSIST:
- launchAssistAction(null, deviceId, eventTime);
+ launchAssistAction(null, deviceId, eventTime,
+ AssistUtils.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
break;
case LONG_PRESS_HOME_NOTIFICATION_PANEL:
toggleNotificationPanel();
@@ -2772,7 +2776,7 @@
} else if (mPendingMetaAction) {
launchAssistAction(Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD,
event.getDeviceId(),
- event.getEventTime());
+ event.getEventTime(), AssistUtils.INVOCATION_TYPE_UNKNOWN);
mPendingMetaAction = false;
}
}
@@ -3036,7 +3040,8 @@
// various parts of the UI.
/** Asks the status bar to startAssist(), usually a full "assistant" interface */
- private void launchAssistAction(String hint, int deviceId, long eventTime) {
+ private void launchAssistAction(String hint, int deviceId, long eventTime,
+ int invocationType) {
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);
if (!isUserSetupComplete()) {
// Disable opening assist window during setup
@@ -3053,6 +3058,7 @@
args.putBoolean(hint, true);
}
args.putLong(Intent.EXTRA_TIME, eventTime);
+ args.putInt(AssistUtils.INVOCATION_TYPE_KEY, invocationType);
((SearchManager) mContext.createContextAsUser(UserHandle.of(mCurrentUserId), 0)
.getSystemService(Context.SEARCH_SERVICE)).launchAssist(args);
diff --git a/services/core/java/com/android/server/power/WakeLockLog.java b/services/core/java/com/android/server/power/WakeLockLog.java
index d6060fa..88c9850 100644
--- a/services/core/java/com/android/server/power/WakeLockLog.java
+++ b/services/core/java/com/android/server/power/WakeLockLog.java
@@ -16,16 +16,12 @@
package com.android.server.power;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
import android.os.PowerManager;
import android.text.TextUtils;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
-import com.android.internal.os.SomeArgs;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
@@ -74,8 +70,6 @@
private static final boolean DEBUG = false;
- private static final int MSG_ON_WAKE_LOCK_EVENT = 1;
-
private static final int TYPE_TIME_RESET = 0x0;
private static final int TYPE_ACQUIRE = 0x1;
private static final int TYPE_RELEASE = 0x2;
@@ -130,7 +124,6 @@
private final Injector mInjector;
private final TheLog mLog;
private final TagDatabase mTagDatabase;
- private final Handler mHandler;
private final SimpleDateFormat mDumpsysDateFormat;
WakeLockLog() {
@@ -140,7 +133,6 @@
@VisibleForTesting
WakeLockLog(Injector injector) {
mInjector = injector;
- mHandler = new WakeLockLogHandler(injector.getLooper());
mTagDatabase = new TagDatabase(injector);
EntryByteTranslator translator = new EntryByteTranslator(mTagDatabase);
mLog = new TheLog(injector, translator, mTagDatabase);
@@ -172,7 +164,7 @@
* Dumps all the wake lock data currently saved in the wake lock log to the specified
* {@code PrintWriter}.
*
- * @param The {@code PrintWriter} to write to.
+ * @param pw The {@code PrintWriter} to write to.
*/
public void dump(PrintWriter pw) {
dump(pw, false);
@@ -221,9 +213,6 @@
/**
* Adds a new entry to the log based on the specified wake lock parameters.
*
- * Grabs the current time for the event and then posts the rest of the logic (actually
- * adding it to the log) to a background thread.
- *
* @param eventType The type of event (ACQUIRE, RELEASE);
* @param tag The wake lock's identifying tag.
* @param ownerUid The owner UID of the wake lock.
@@ -239,15 +228,11 @@
}
final long time = mInjector.currentTimeMillis();
-
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = tagNameReducer(tag);
- args.argi1 = eventType;
- args.argi2 = ownerUid;
- args.argi3 = eventType == TYPE_ACQUIRE ? translateFlagsFromPowerManager(flags) : 0;
- args.argi4 = (int) ((time >> 32) & 0xFFFFFFFFL);
- args.argi5 = (int) (time & 0xFFFFFFFFL);
- mHandler.obtainMessage(MSG_ON_WAKE_LOCK_EVENT, args).sendToTarget();
+ final int translatedFlags = eventType == TYPE_ACQUIRE
+ ? translateFlagsFromPowerManager(flags)
+ : 0;
+ handleWakeLockEventInternal(eventType, tagNameReducer(tag), ownerUid, translatedFlags,
+ time);
}
/**
@@ -273,8 +258,8 @@
* flags, {@code WakeLockLog.FLAG_*}, and a log-level, {@code WakeLockLog.LEVEL_*}.
*
* @param flags Wake lock flags including {@code PowerManager.*_WAKE_LOCK}
- * {@link PowerManager.ACQUIRE_CAUSES_WAKEUP}, and
- * {@link PowerManager.ON_AFTER_RELEASE}.
+ * {@link PowerManager#ACQUIRE_CAUSES_WAKEUP}, and
+ * {@link PowerManager#ON_AFTER_RELEASE}.
* @return The compressed flags value.
*/
int translateFlagsFromPowerManager(int flags) {
@@ -328,9 +313,9 @@
}
String reduciblePrefix = null;
- for (int tp = 0; tp < REDUCED_TAG_PREFIXES.length; tp++) {
- if (tag.startsWith(REDUCED_TAG_PREFIXES[tp])) {
- reduciblePrefix = REDUCED_TAG_PREFIXES[tp];
+ for (String reducedTagPrefix : REDUCED_TAG_PREFIXES) {
+ if (tag.startsWith(reducedTagPrefix)) {
+ reduciblePrefix = reducedTagPrefix;
break;
}
}
@@ -339,7 +324,7 @@
final StringBuilder sb = new StringBuilder();
// add prefix first
- sb.append(tag.substring(0, reduciblePrefix.length()));
+ sb.append(tag, 0, reduciblePrefix.length());
// Stop looping on final marker
final int end = Math.max(tag.lastIndexOf("/"), tag.lastIndexOf("."));
@@ -604,7 +589,7 @@
* @return The number of bytes written to buffer, or required to write to the buffer.
*/
int toBytes(LogEntry entry, byte[] bytes, long timeReference) {
- int sizeNeeded = -1;
+ final int sizeNeeded;
switch (entry.type) {
case TYPE_ACQUIRE: {
sizeNeeded = 3;
@@ -696,8 +681,9 @@
* {@link EntryByteTranslator} to convert byte {@link LogEntry} to bytes within the buffer.
*
* This class also implements the logic around TIME_RESET events. Since the LogEntries store
- * their time (8-bit) relative to the previous event, this class can add {@link TYPE_TIME_RESET}
- * LogEntries as necessary to allow a LogEntry's relative time to fit within that range.
+ * their time (8-bit) relative to the previous event, this class can add
+ * {@link #TYPE_TIME_RESET} LogEntries as necessary to allow a LogEntry's relative time to fit
+ * within that range.
*/
static class TheLog {
private final EntryByteTranslator mTranslator;
@@ -711,7 +697,7 @@
/**
* Second temporary buffer used when reading and writing bytes from the buffer.
* A second temporary buffer is necessary since additional items can be read concurrently
- * from {@link mTempBuffer}. E.g., Adding an entry to a full buffer requires removing
+ * from {@link #mTempBuffer}. E.g., Adding an entry to a full buffer requires removing
* other entries from the buffer.
*/
private final byte[] mReadWriteTempBuffer = new byte[MAX_LOG_ENTRY_BYTE_SIZE];
@@ -832,7 +818,7 @@
* Returns an {@link Iterator} of {@link LogEntry}s for all the entries in the log.
*
* If the log is modified while the entries are being read, the iterator will throw a
- * {@link ConcurrentModificationExceptoin}.
+ * {@link ConcurrentModificationException}.
*
* @param tempEntry A temporary {@link LogEntry} instance to use so that new instances
* aren't allocated with every call to {@code Iterator.next}.
@@ -1063,7 +1049,7 @@
* instanced into bytes.
*
* If a new tag is added when the database is full, the oldest tag is removed. The oldest tag
- * is calcualted using {@link TagData.lastUsedTime}.
+ * is calculated using {@link TagData#lastUsedTime}.
*/
static class TagDatabase {
private final int mInvalidIndex;
@@ -1086,9 +1072,9 @@
int byteEstimate = 0;
int tagSize = 0;
int tags = 0;
- for (int i = 0; i < mArray.length; i++) {
+ for (TagData tagData : mArray) {
byteEstimate += 8; // reference pointer
- TagData data = mArray[i];
+ TagData data = tagData;
if (data != null) {
entries++;
byteEstimate += data.getByteSize();
@@ -1280,10 +1266,6 @@
@Override
public String toString() {
- StringBuilder sb = new StringBuilder();
- if (DEBUG) {
- sb.append("(").append(index).append(")");
- }
return "[" + ownerUid + " ; " + tag + "]";
}
@@ -1308,10 +1290,6 @@
* Injector used by {@link WakeLockLog} for testing purposes.
*/
public static class Injector {
- public Looper getLooper() {
- return BackgroundThread.get().getLooper();
- }
-
public int getTagDatabaseSize() {
return TAG_DATABASE_SIZE;
}
@@ -1328,28 +1306,4 @@
return DATE_FORMAT;
}
}
-
- private class WakeLockLogHandler extends Handler {
- WakeLockLogHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message message) {
- switch(message.what) {
- case MSG_ON_WAKE_LOCK_EVENT:
- final SomeArgs args = (SomeArgs) message.obj;
- final String tag = (String) args.arg1;
- final int eventType = args.argi1;
- final int ownerUid = args.argi2;
- final int flags = args.argi3;
- final long time = (((long) args.argi4) << 32) + (args.argi5 & 0xFFFFFFFFL);
- args.recycle();
- handleWakeLockEventInternal(eventType, tag, ownerUid, flags, time);
- break;
- default:
- break;
- }
- }
- }
}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index a82c91e..dc868b3 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -126,6 +126,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.connectivity.WifiActivityEnergyInfo;
+import android.os.incremental.IncrementalManager;
import android.os.storage.DiskInfo;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
@@ -426,6 +427,7 @@
private final Object mHealthHalLock = new Object();
private final Object mAttributedAppOpsLock = new Object();
private final Object mSettingsStatsLock = new Object();
+ private final Object mInstalledIncrementalPackagesLock = new Object();
public StatsPullAtomService(Context context) {
super(context);
@@ -695,6 +697,10 @@
synchronized (mSettingsStatsLock) {
return pullSettingsStatsLocked(atomTag, data);
}
+ case FrameworkStatsLog.INSTALLED_INCREMENTAL_PACKAGE:
+ synchronized (mInstalledIncrementalPackagesLock) {
+ return pullInstalledIncrementalPackagesLocked(atomTag, data);
+ }
default:
throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
}
@@ -877,6 +883,7 @@
registerBatteryVoltage();
registerBatteryCycleCount();
registerSettingsStats();
+ registerInstalledIncrementalPackages();
}
private void initAndRegisterNetworkStatsPullers() {
@@ -3949,6 +3956,31 @@
return StatsManager.PULL_SUCCESS;
}
+ private void registerInstalledIncrementalPackages() {
+ int tagId = FrameworkStatsLog.INSTALLED_INCREMENTAL_PACKAGE;
+ mStatsManager.setPullAtomCallback(
+ tagId,
+ null, // use default PullAtomMetadata values
+ DIRECT_EXECUTOR,
+ mStatsCallbackImpl
+ );
+ }
+
+ int pullInstalledIncrementalPackagesLocked(int atomTag, List<StatsEvent> pulledData) {
+ final PackageManager pm = mContext.getPackageManager();
+ if (!pm.hasSystemFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY)) {
+ // Incremental is not enabled on this device. The result list will be empty.
+ return StatsManager.PULL_SUCCESS;
+ }
+ List<PackageInfo> installedPackages = pm.getInstalledPackages(0);
+ for (PackageInfo pi : installedPackages) {
+ if (IncrementalManager.isIncrementalPath(pi.applicationInfo.getBaseCodePath())) {
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, pi.applicationInfo.uid));
+ }
+ }
+ return StatsManager.PULL_SUCCESS;
+ }
+
// Thermal event received from vendor thermal management subsystem
private static final class ThermalEventListener extends IThermalEventListener.Stub {
@Override
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 50749a9..9d8b8f7 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -372,7 +372,7 @@
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
R.anim.screen_rotate_0_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
- R.anim.screen_rotate_0_enter);
+ R.anim.rotation_animation_enter);
break;
case Surface.ROTATION_90:
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index 68cb8f9..3dc7bc1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -48,14 +48,18 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.job.JobInfo;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.PackageManagerInternal;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkPolicyManager;
+import android.os.BatteryManager;
+import android.os.BatteryManagerInternal;
import android.os.Build;
import android.os.Looper;
import android.os.SystemClock;
@@ -70,6 +74,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatchers;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@@ -83,6 +88,8 @@
@Mock
private Context mContext;
@Mock
+ private BatteryManagerInternal mBatteryManagerInternal;
+ @Mock
private ConnectivityManager mConnManager;
@Mock
private NetworkPolicyManager mNetPolicyManager;
@@ -108,6 +115,9 @@
LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
LocalServices.addService(NetworkPolicyManagerInternal.class, mNetPolicyManagerInternal);
+ LocalServices.removeServiceForTest(BatteryManagerInternal.class);
+ LocalServices.addService(BatteryManagerInternal.class, mBatteryManagerInternal);
+
when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
// Freeze the clocks at this moment in time
@@ -143,8 +153,18 @@
DataUnit.MEBIBYTES.toBytes(1))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
+ final ArgumentCaptor<BroadcastReceiver> chargingCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ when(mBatteryManagerInternal.isPowered(eq(BatteryManager.BATTERY_PLUGGED_ANY)))
+ .thenReturn(false);
final ConnectivityController controller = new ConnectivityController(mService);
+ verify(mContext).registerReceiver(chargingCaptor.capture(),
+ ArgumentMatchers.argThat(filter ->
+ filter.hasAction(BatteryManager.ACTION_CHARGING)
+ && filter.hasAction(BatteryManager.ACTION_DISCHARGING)));
when(mService.getMaxJobExecutionTimeMs(any())).thenReturn(10 * 60_000L);
+ final BroadcastReceiver chargingReceiver = chargingCaptor.getValue();
+ chargingReceiver.onReceive(mContext, new Intent(BatteryManager.ACTION_DISCHARGING));
// Slow network is too slow
assertFalse(controller.isSatisfied(createJobStatus(job), net,
@@ -166,7 +186,18 @@
assertTrue(controller.isSatisfied(createJobStatus(job), net,
createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(130)
.setLinkDownstreamBandwidthKbps(130).build(), mConstants));
+ // Slow network is too slow, but device is charging and network is unmetered.
+ when(mBatteryManagerInternal.isPowered(eq(BatteryManager.BATTERY_PLUGGED_ANY)))
+ .thenReturn(true);
+ chargingReceiver.onReceive(mContext, new Intent(BatteryManager.ACTION_CHARGING));
+ assertTrue(controller.isSatisfied(createJobStatus(job), net,
+ createCapabilitiesBuilder().addCapability(NET_CAPABILITY_NOT_METERED)
+ .setLinkUpstreamBandwidthKbps(1).setLinkDownstreamBandwidthKbps(1).build(),
+ mConstants));
+ when(mBatteryManagerInternal.isPowered(eq(BatteryManager.BATTERY_PLUGGED_ANY)))
+ .thenReturn(false);
+ chargingReceiver.onReceive(mContext, new Intent(BatteryManager.ACTION_DISCHARGING));
when(mService.getMaxJobExecutionTimeMs(any())).thenReturn(60_000L);
// Slow network is too slow
@@ -189,6 +220,14 @@
assertFalse(controller.isSatisfied(createJobStatus(job), net,
createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(130)
.setLinkDownstreamBandwidthKbps(130).build(), mConstants));
+ // Slow network is too slow, but device is charging and network is unmetered.
+ when(mBatteryManagerInternal.isPowered(eq(BatteryManager.BATTERY_PLUGGED_ANY)))
+ .thenReturn(true);
+ chargingReceiver.onReceive(mContext, new Intent(BatteryManager.ACTION_CHARGING));
+ assertTrue(controller.isSatisfied(createJobStatus(job), net,
+ createCapabilitiesBuilder().addCapability(NET_CAPABILITY_NOT_METERED)
+ .setLinkUpstreamBandwidthKbps(1).setLinkDownstreamBandwidthKbps(1).build(),
+ mConstants));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/am/FgsTempAllowListTest.java b/services/tests/servicestests/src/com/android/server/am/FgsTempAllowListTest.java
index f85f0f8..50d4d84 100644
--- a/services/tests/servicestests/src/com/android/server/am/FgsTempAllowListTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/FgsTempAllowListTest.java
@@ -29,6 +29,9 @@
import org.junit.Test;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+
/**
* Build/Install/Run:
* atest FrameworksServicesTests:TempAllowListTest
@@ -41,7 +44,7 @@
*/
@Test
public void testIsAllowed() {
- FgsTempAllowList<Integer, String> allowList = new FgsTempAllowList();
+ FgsTempAllowList<String> allowList = new FgsTempAllowList();
allowList.add(10001, 2000, "description1");
allowList.add(10002, 2000, "description2");
@@ -55,7 +58,7 @@
assertNotNull(entry2);
assertEquals(entry2.second, "description2");
- allowList.remove(10001);
+ allowList.removeUid(10001);
assertFalse(allowList.isAllowed(10001));
assertNull(allowList.get(10001));
}
@@ -65,7 +68,7 @@
*/
@Test
public void testExpired() {
- FgsTempAllowList<Integer, String> allowList = new FgsTempAllowList();
+ FgsTempAllowList<String> allowList = new FgsTempAllowList();
// temp allow for 2000ms.
allowList.add(10001, 2000, "uid1-2000ms");
// sleep for 3000ms.
@@ -74,4 +77,51 @@
assertFalse(allowList.isAllowed(10001));
assertNull(allowList.get(10001));
}
+
+ @Test
+ public void testRemoveAppId() {
+ FgsTempAllowList<String> allowList = new FgsTempAllowList();
+ allowList.add(10001, 2000, "description1");
+ allowList.add(10002, 2000, "description2");
+ allowList.add(10_10001, 2000, "description3");
+
+ assertTrue(allowList.isAllowed(10001));
+ assertTrue(allowList.isAllowed(10002));
+ assertTrue(allowList.isAllowed(10_10001));
+
+ allowList.removeAppId(10001);
+
+ assertFalse(allowList.isAllowed(10001));
+ assertTrue(allowList.isAllowed(10002));
+ assertFalse(allowList.isAllowed(10_10001));
+ }
+
+ @Test
+ public void testForEach() {
+ final FgsTempAllowList<String> allowList = new FgsTempAllowList();
+
+
+ // Call forEach(), return the sum of all the UIDs, and make sure the item is
+ // "uid" + uid.
+ final Supplier<Integer> callForEach = () -> {
+ final AtomicInteger sum = new AtomicInteger();
+ sum.set(0);
+ allowList.forEach((uid, entry) -> {
+ sum.set(sum.get() + uid);
+ assertEquals(entry.second, "uid" + uid);
+ });
+ return sum.get();
+ };
+
+ // Call on th empty list.
+ assertEquals(0, (int) callForEach.get());
+
+ // Add one item.
+ allowList.add(1, 2000, "uid1");
+ assertEquals(1, (int) callForEach.get());
+
+ // Add one more item.
+ allowList.add(10, 2000, "uid10");
+ assertEquals(11, (int) callForEach.get());
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
index 4cd17e8..b820df3 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
@@ -37,7 +37,6 @@
import android.os.Looper;
import android.os.PowerManager;
import android.os.test.TestLooper;
-import android.provider.Settings;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -51,6 +50,7 @@
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.Collections;
/** Tests for {@link OneTouchPlayAction} */
@SmallTest
@@ -69,6 +69,7 @@
private Context mContextSpy;
private HdmiControlService mHdmiControlService;
private FakeNativeWrapper mNativeWrapper;
+ private FakeHdmiCecConfig mHdmiCecConfig;
private TestLooper mTestLooper = new TestLooper();
private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
@@ -88,6 +89,7 @@
MockitoAnnotations.initMocks(this);
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
+ mHdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
setHdmiControlEnabled(hdmiControlEnabled);
@@ -99,7 +101,7 @@
mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
when(mIPowerManagerMock.isInteractive()).thenReturn(true);
- mHdmiControlService = new HdmiControlService(mContextSpy) {
+ mHdmiControlService = new HdmiControlService(mContextSpy, Collections.emptyList()) {
@Override
AudioManager getAudioManager() {
return new AudioManager() {
@@ -134,7 +136,7 @@
Looper looper = mTestLooper.getLooper();
mHdmiControlService.setIoLooper(looper);
- mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
+ mHdmiControlService.setHdmiCecConfig(mHdmiCecConfig);
mNativeWrapper = new FakeNativeWrapper();
HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
@@ -479,7 +481,7 @@
mTestLooper.dispatchAll();
assertThat(callback.hasResult()).isFalse();
- assertThat(playbackDevice.isActiveSource()).isFalse();
+ mNativeWrapper.clearResultMessages();
setHdmiControlEnabled(true);
mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
@@ -498,6 +500,12 @@
assertThat(mHdmiControlService.isAddressAllocated()).isTrue();
assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
assertThat(playbackDevice.isActiveSource()).isTrue();
+ HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
+ playbackDevice.mAddress, mPhysicalAddress);
+ HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress,
+ ADDR_TV);
+ assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
+ assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
}
@Test
@@ -527,6 +535,12 @@
assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
assertThat(playbackDevice.isActiveSource()).isTrue();
+ HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
+ playbackDevice.mAddress, mPhysicalAddress);
+ HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress,
+ ADDR_TV);
+ assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
+ assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
}
@Test
@@ -602,8 +616,8 @@
}
private void setHdmiControlEnabled(boolean enabled) {
- int value = enabled ? 1 : 0;
- Settings.Global.putInt(mContextSpy.getContentResolver(),
- Settings.Global.HDMI_CONTROL_ENABLED, value);
+ int value = enabled ? HdmiControlManager.HDMI_CEC_CONTROL_ENABLED :
+ HdmiControlManager.HDMI_CEC_CONTROL_DISABLED;
+ mHdmiCecConfig.setIntValue(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, value);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index aecc794..b01c1c8 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -165,7 +165,17 @@
mRebootEscrow = null;
mServerBased = true;
RebootEscrowProviderServerBasedImpl.Injector injector =
- new RebootEscrowProviderServerBasedImpl.Injector(serviceConnection);
+ new RebootEscrowProviderServerBasedImpl.Injector(serviceConnection) {
+ @Override
+ long getServiceTimeoutInSeconds() {
+ return 30;
+ }
+
+ @Override
+ long getServerBlobLifetimeInMillis() {
+ return 600_000;
+ }
+ };
mDefaultRebootEscrowProvider = new RebootEscrowProviderServerBasedImpl(
storage, injector);
mUserManager = userManager;
@@ -189,6 +199,11 @@
}
@Override
+ public boolean isNetworkConnected() {
+ return false;
+ }
+
+ @Override
public RebootEscrowProviderInterface createRebootEscrowProviderIfNeeded() {
mRebootEscrowProviderInUse = mDefaultRebootEscrowProvider;
return mRebootEscrowProviderInUse;
@@ -602,7 +617,7 @@
// Sleep 5s for the retry to complete
Thread.sleep(5 * 1000);
assertFalse(metricsSuccessCaptor.getValue());
- assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_RETRY_COUNT_EXHAUSTED),
+ assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_NO_NETWORK),
metricsErrorCodeCaptor.getValue());
}
diff --git a/services/tests/servicestests/src/com/android/server/power/WakeLockLogTest.java b/services/tests/servicestests/src/com/android/server/power/WakeLockLogTest.java
index a03ba9c..09612e3 100644
--- a/services/tests/servicestests/src/com/android/server/power/WakeLockLogTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/WakeLockLogTest.java
@@ -20,12 +20,8 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
-import android.os.Looper;
import android.os.PowerManager;
-import android.os.test.TestLooper;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Test;
import java.io.PrintWriter;
@@ -38,17 +34,6 @@
*/
public class WakeLockLogTest {
- private TestLooper mTestLooper;
-
- @Before
- public void setUp() throws Exception {
- mTestLooper = new TestLooper();
- }
-
- @After
- public void tearDown() throws Exception {
- }
-
@Test
public void testAddTwoItems() {
final int tagDatabaseSize = 128;
@@ -70,7 +55,7 @@
+ " -\n"
+ " Events: 2, Time-Resets: 0\n"
+ " Buffer, Bytes used: 6\n",
- dispatchAndDump(log, false));
+ dumpLog(log, false));
}
@Test
@@ -92,7 +77,7 @@
+ " -\n"
+ " Events: 2, Time-Resets: 1\n"
+ " Buffer, Bytes used: 15\n",
- dispatchAndDump(log, false));
+ dumpLog(log, false));
}
@Test
@@ -114,7 +99,7 @@
+ " -\n"
+ " Events: 2, Time-Resets: 0\n"
+ " Buffer, Bytes used: 6\n",
- dispatchAndDump(log, false));
+ dumpLog(log, false));
}
@Test
@@ -142,7 +127,7 @@
+ " -\n"
+ " Events: 3, Time-Resets: 0\n"
+ " Buffer, Bytes used: 9\n",
- dispatchAndDump(log, false));
+ dumpLog(log, false));
}
@Test
@@ -160,7 +145,7 @@
+ " -\n"
+ " Events: 0, Time-Resets: 0\n"
+ " Buffer, Bytes used: 0\n",
- dispatchAndDump(log, false));
+ dumpLog(log, false));
}
@Test
@@ -179,7 +164,7 @@
+ " -\n"
+ " Events: 1, Time-Resets: 0\n"
+ " Buffer, Bytes used: 3\n",
- dispatchAndDump(log, false));
+ dumpLog(log, false));
}
@Test
@@ -201,7 +186,7 @@
+ " Events: 2, Time-Resets: 0\n"
+ " Buffer, Bytes used: 5\n"
+ " Tag Database: size(5), entries: 1, Bytes used: 80\n",
- dispatchAndDump(log, true));
+ dumpLog(log, true));
}
@Test
@@ -223,11 +208,10 @@
+ " -\n"
+ " Events: 1, Time-Resets: 0\n"
+ " Buffer, Bytes used: 3\n",
- dispatchAndDump(log, false));
+ dumpLog(log, false));
}
- private String dispatchAndDump(WakeLockLog log, boolean includeTagDb) {
- mTestLooper.dispatchAll();
+ private String dumpLog(WakeLockLog log, boolean includeTagDb) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
log.dump(pw, includeTagDb);
@@ -244,11 +228,6 @@
}
@Override
- public Looper getLooper() {
- return mTestLooper.getLooper();
- }
-
- @Override
public int getTagDatabaseSize() {
return mTagDatabaseSize;
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index c527e66..6b7fc2f 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3682,6 +3682,13 @@
"emergency_number_prefix_string_array";
/**
+ * Indicates whether carrier treats "*67" or "*82" as a temporary mode CLIR.
+ * @hide
+ */
+ public static final String KEY_CARRIER_SUPPORTS_CALLER_ID_VERTICAL_SERVICE_CODES_BOOL =
+ "carrier_supports_caller_id_vertical_service_codes_bool";
+
+ /**
* Smart forwarding config. Smart forwarding is a feature to configure call forwarding to a
* different SIM in the device when one SIM is not reachable. The config here specifies a smart
* forwarding component that will launch UI for changing the configuration. An empty string
@@ -5496,6 +5503,7 @@
1 /* Roaming Indicator Off */
});
sDefaults.putStringArray(KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY, new String[0]);
+ sDefaults.putBoolean(KEY_CARRIER_SUPPORTS_CALLER_ID_VERTICAL_SERVICE_CODES_BOOL, false);
sDefaults.putBoolean(KEY_USE_USIM_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL, false);
sDefaults.putBoolean(KEY_AUTO_CANCEL_CS_REJECT_NOTIFICATION, true);
diff --git a/telephony/java/android/telephony/ims/DelegateStateCallback.java b/telephony/java/android/telephony/ims/DelegateStateCallback.java
index 2b4fb7d..734b520 100644
--- a/telephony/java/android/telephony/ims/DelegateStateCallback.java
+++ b/telephony/java/android/telephony/ims/DelegateStateCallback.java
@@ -79,7 +79,7 @@
* messages routing should be delayed until the {@link SipDelegate} sends the IMS configuration
* change event to reduce conditions where the remote application is using a stale IMS
* configuration.
- * @deprecated This is being removed from API surface, Use
+ * @removed This is being removed from API surface, Use
* {@link #onConfigurationChanged(SipDelegateConfiguration)} instead.
*/
@Deprecated
diff --git a/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java b/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java
index 08513c2..fe14dd1 100644
--- a/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java
+++ b/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java
@@ -34,7 +34,7 @@
/**
* @hide
- * @deprecated Use {@link SipDelegateConfiguration} instead.
+ * @removed Use {@link SipDelegateConfiguration} instead.
*/
@Deprecated
@SystemApi
diff --git a/telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java b/telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java
index c078637..42c53f2 100644
--- a/telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java
+++ b/telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java
@@ -136,7 +136,7 @@
* not compleed yet.
*
* @param registeredSipConfig The configuration of the IMS stack registered on the IMS network.
- * @deprecated Will not be in final API, use
+ * @removed Will not be in final API, use
* {@link #onConfigurationChanged(SipDelegateConfiguration)} instead}.
*/
@Deprecated
@@ -161,7 +161,7 @@
*
* @param registeredSipConfig The configuration of the IMS stack registered on the IMS network.
*/
- default void onConfigurationChanged(@NonNull SipDelegateConfiguration registeredSipConfig) {}
+ void onConfigurationChanged(@NonNull SipDelegateConfiguration registeredSipConfig);
/**
* The previously created {@link SipDelegateConnection} instance delivered via
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 91ecbf0..a096c1f 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2440,6 +2440,12 @@
boolean removeUceRequestDisallowedStatus(int subId);
/**
+ * Set the timeout for contact capabilities request.
+ * Note: This is designed for a SHELL command only.
+ */
+ boolean setCapabilitiesRequestTimeout(int subId, long timeoutAfterMs);
+
+ /**
* Set a SignalStrengthUpdateRequest to receive notification when Signal Strength breach the
* specified thresholds.
*/
diff --git a/tools/aosp/aosp_sha.sh b/tools/aosp/aosp_sha.sh
index 99aaa3c..81d35ef 100755
--- a/tools/aosp/aosp_sha.sh
+++ b/tools/aosp/aosp_sha.sh
@@ -4,6 +4,9 @@
if git branch -vv | grep -q -P "^\*[^\[]+\[aosp/"; then
# Change appears to be in AOSP
exit 0
+elif git log -n 1 --format='%B' $1 | grep -q -E "^Ignore-AOSP-First: .+" ; then
+ # Change is explicitly marked as ok to skip AOSP
+ exit 0
else
# Change appears to be non-AOSP; search for files
count=0
diff --git a/tools/apilint/deprecated_at_birth.py b/tools/apilint/deprecated_at_birth.py
new file mode 100644
index 0000000..297d9c3b
--- /dev/null
+++ b/tools/apilint/deprecated_at_birth.py
@@ -0,0 +1,313 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2021 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.
+
+"""
+Usage: deprecated_at_birth.py path/to/next/ path/to/previous/
+Usage: deprecated_at_birth.py prebuilts/sdk/31/public/api/ prebuilts/sdk/30/public/api/
+"""
+
+import re, sys, os, collections, traceback, argparse
+
+
+BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
+
+def format(fg=None, bg=None, bright=False, bold=False, dim=False, reset=False):
+ # manually derived from http://en.wikipedia.org/wiki/ANSI_escape_code#Codes
+ codes = []
+ if reset: codes.append("0")
+ else:
+ if not fg is None: codes.append("3%d" % (fg))
+ if not bg is None:
+ if not bright: codes.append("4%d" % (bg))
+ else: codes.append("10%d" % (bg))
+ if bold: codes.append("1")
+ elif dim: codes.append("2")
+ else: codes.append("22")
+ return "\033[%sm" % (";".join(codes))
+
+
+def ident(raw):
+ """Strips superficial signature changes, giving us a strong key that
+ can be used to identify members across API levels."""
+ raw = raw.replace(" deprecated ", " ")
+ raw = raw.replace(" synchronized ", " ")
+ raw = raw.replace(" final ", " ")
+ raw = re.sub("<.+?>", "", raw)
+ raw = re.sub("@[A-Za-z]+ ", "", raw)
+ raw = re.sub("@[A-Za-z]+\(.+?\) ", "", raw)
+ if " throws " in raw:
+ raw = raw[:raw.index(" throws ")]
+ return raw
+
+
+class Field():
+ def __init__(self, clazz, line, raw, blame):
+ self.clazz = clazz
+ self.line = line
+ self.raw = raw.strip(" {;")
+ self.blame = blame
+
+ raw = raw.split()
+ self.split = list(raw)
+
+ raw = [ r for r in raw if not r.startswith("@") ]
+ for r in ["method", "field", "public", "protected", "static", "final", "abstract", "default", "volatile", "transient"]:
+ while r in raw: raw.remove(r)
+
+ self.typ = raw[0]
+ self.name = raw[1].strip(";")
+ if len(raw) >= 4 and raw[2] == "=":
+ self.value = raw[3].strip(';"')
+ else:
+ self.value = None
+ self.ident = ident(self.raw)
+
+ def __hash__(self):
+ return hash(self.raw)
+
+ def __repr__(self):
+ return self.raw
+
+
+class Method():
+ def __init__(self, clazz, line, raw, blame):
+ self.clazz = clazz
+ self.line = line
+ self.raw = raw.strip(" {;")
+ self.blame = blame
+
+ # drop generics for now
+ raw = re.sub("<.+?>", "", raw)
+
+ raw = re.split("[\s(),;]+", raw)
+ for r in ["", ";"]:
+ while r in raw: raw.remove(r)
+ self.split = list(raw)
+
+ raw = [ r for r in raw if not r.startswith("@") ]
+ for r in ["method", "field", "public", "protected", "static", "final", "abstract", "default", "volatile", "transient"]:
+ while r in raw: raw.remove(r)
+
+ self.typ = raw[0]
+ self.name = raw[1]
+ self.args = []
+ self.throws = []
+ target = self.args
+ for r in raw[2:]:
+ if r == "throws": target = self.throws
+ else: target.append(r)
+ self.ident = ident(self.raw)
+
+ def __hash__(self):
+ return hash(self.raw)
+
+ def __repr__(self):
+ return self.raw
+
+
+class Class():
+ def __init__(self, pkg, line, raw, blame):
+ self.pkg = pkg
+ self.line = line
+ self.raw = raw.strip(" {;")
+ self.blame = blame
+ self.ctors = []
+ self.fields = []
+ self.methods = []
+
+ raw = raw.split()
+ self.split = list(raw)
+ if "class" in raw:
+ self.fullname = raw[raw.index("class")+1]
+ elif "enum" in raw:
+ self.fullname = raw[raw.index("enum")+1]
+ elif "interface" in raw:
+ self.fullname = raw[raw.index("interface")+1]
+ elif "@interface" in raw:
+ self.fullname = raw[raw.index("@interface")+1]
+ else:
+ raise ValueError("Funky class type %s" % (self.raw))
+
+ if "extends" in raw:
+ self.extends = raw[raw.index("extends")+1]
+ self.extends_path = self.extends.split(".")
+ else:
+ self.extends = None
+ self.extends_path = []
+
+ self.fullname = self.pkg.name + "." + self.fullname
+ self.fullname_path = self.fullname.split(".")
+
+ self.name = self.fullname[self.fullname.rindex(".")+1:]
+
+ def __hash__(self):
+ return hash((self.raw, tuple(self.ctors), tuple(self.fields), tuple(self.methods)))
+
+ def __repr__(self):
+ return self.raw
+
+
+class Package():
+ def __init__(self, line, raw, blame):
+ self.line = line
+ self.raw = raw.strip(" {;")
+ self.blame = blame
+
+ raw = raw.split()
+ self.name = raw[raw.index("package")+1]
+ self.name_path = self.name.split(".")
+
+ def __repr__(self):
+ return self.raw
+
+
+def _parse_stream(f, api={}):
+ line = 0
+ pkg = None
+ clazz = None
+ blame = None
+
+ re_blame = re.compile("^([a-z0-9]{7,}) \(<([^>]+)>.+?\) (.+?)$")
+ for raw in f:
+ line += 1
+ raw = raw.rstrip()
+ match = re_blame.match(raw)
+ if match is not None:
+ blame = match.groups()[0:2]
+ raw = match.groups()[2]
+ else:
+ blame = None
+
+ if raw.startswith("package"):
+ pkg = Package(line, raw, blame)
+ elif raw.startswith(" ") and raw.endswith("{"):
+ clazz = Class(pkg, line, raw, blame)
+ api[clazz.fullname] = clazz
+ elif raw.startswith(" ctor"):
+ clazz.ctors.append(Method(clazz, line, raw, blame))
+ elif raw.startswith(" method"):
+ clazz.methods.append(Method(clazz, line, raw, blame))
+ elif raw.startswith(" field"):
+ clazz.fields.append(Field(clazz, line, raw, blame))
+
+ return api
+
+
+def _parse_stream_path(path):
+ api = {}
+ print "Parsing", path
+ for f in os.listdir(path):
+ f = os.path.join(path, f)
+ if not os.path.isfile(f): continue
+ if not f.endswith(".txt"): continue
+ if f.endswith("removed.txt"): continue
+ print "\t", f
+ with open(f) as s:
+ api = _parse_stream(s, api)
+ print "Parsed", len(api), "APIs"
+ print
+ return api
+
+
+class Failure():
+ def __init__(self, sig, clazz, detail, error, rule, msg):
+ self.sig = sig
+ self.error = error
+ self.rule = rule
+ self.msg = msg
+
+ if error:
+ self.head = "Error %s" % (rule) if rule else "Error"
+ dump = "%s%s:%s %s" % (format(fg=RED, bg=BLACK, bold=True), self.head, format(reset=True), msg)
+ else:
+ self.head = "Warning %s" % (rule) if rule else "Warning"
+ dump = "%s%s:%s %s" % (format(fg=YELLOW, bg=BLACK, bold=True), self.head, format(reset=True), msg)
+
+ self.line = clazz.line
+ blame = clazz.blame
+ if detail is not None:
+ dump += "\n in " + repr(detail)
+ self.line = detail.line
+ blame = detail.blame
+ dump += "\n in " + repr(clazz)
+ dump += "\n in " + repr(clazz.pkg)
+ dump += "\n at line " + repr(self.line)
+ if blame is not None:
+ dump += "\n last modified by %s in %s" % (blame[1], blame[0])
+
+ self.dump = dump
+
+ def __repr__(self):
+ return self.dump
+
+
+failures = {}
+
+def _fail(clazz, detail, error, rule, msg):
+ """Records an API failure to be processed later."""
+ global failures
+
+ sig = "%s-%s-%s" % (clazz.fullname, repr(detail), msg)
+ sig = sig.replace(" deprecated ", " ")
+
+ failures[sig] = Failure(sig, clazz, detail, error, rule, msg)
+
+
+def warn(clazz, detail, rule, msg):
+ _fail(clazz, detail, False, rule, msg)
+
+def error(clazz, detail, rule, msg):
+ _fail(clazz, detail, True, rule, msg)
+
+
+if __name__ == "__main__":
+ next_path = sys.argv[1]
+ prev_path = sys.argv[2]
+
+ next_api = _parse_stream_path(next_path)
+ prev_api = _parse_stream_path(prev_path)
+
+ # Remove all existing things so we're left with new
+ for prev_clazz in prev_api.values():
+ if prev_clazz.fullname not in next_api: continue
+ cur_clazz = next_api[prev_clazz.fullname]
+
+ sigs = { i.ident: i for i in prev_clazz.ctors }
+ cur_clazz.ctors = [ i for i in cur_clazz.ctors if i.ident not in sigs ]
+ sigs = { i.ident: i for i in prev_clazz.methods }
+ cur_clazz.methods = [ i for i in cur_clazz.methods if i.ident not in sigs ]
+ sigs = { i.ident: i for i in prev_clazz.fields }
+ cur_clazz.fields = [ i for i in cur_clazz.fields if i.ident not in sigs ]
+
+ # Forget about class entirely when nothing new
+ if len(cur_clazz.ctors) == 0 and len(cur_clazz.methods) == 0 and len(cur_clazz.fields) == 0:
+ del next_api[prev_clazz.fullname]
+
+ for clazz in next_api.values():
+ if "@Deprecated " in clazz.raw and not clazz.fullname in prev_api:
+ error(clazz, None, None, "Found API deprecation at birth")
+
+ if "@Deprecated " in clazz.raw: continue
+
+ for i in clazz.ctors + clazz.methods + clazz.fields:
+ if "@Deprecated " in i.raw:
+ error(clazz, i, None, "Found API deprecation at birth " + i.ident)
+
+ print "%s Deprecated at birth %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True),
+ format(reset=True)))
+ for f in sorted(failures):
+ print failures[f]
+ print
diff --git a/wifi/OWNERS b/wifi/OWNERS
index 2caf9ed..777df57 100644
--- a/wifi/OWNERS
+++ b/wifi/OWNERS
@@ -1,5 +1,3 @@
set noparent
-dysu@google.com
-etancohen@google.com
-satk@google.com
+include platform/packages/modules/Wifi:/OWNERS