Merge "Import translations. DO NOT MERGE ANYWHERE" into sc-dev
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 175fb38..65b2511 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -22,7 +22,7 @@
strings_lint_hook = ${REPO_ROOT}/frameworks/base/tools/stringslint/stringslint_sha.sh ${PREUPLOAD_COMMIT}
-hidden_api_txt_checksorted_hook = ${REPO_ROOT}/frameworks/base/tools/hiddenapi/checksorted_sha.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT}
+hidden_api_txt_checksorted_hook = ${REPO_ROOT}/tools/platform-compat/hiddenapi/checksorted_sha.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT}
hidden_api_txt_exclude_hook = ${REPO_ROOT}/frameworks/base/tools/hiddenapi/exclude.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT}
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 23dc720..bc3f131 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -96,6 +96,8 @@
],
api_levels_annotations_enabled: false,
filter_packages: packages_to_document,
+ defaults_visibility: ["//visibility:private"],
+ visibility: ["//frameworks/base/api"],
}
/////////////////////////////////////////////////////////////////////
@@ -352,6 +354,8 @@
tag: ".jar",
dest: "android-non-updatable.jar",
},
+ defaults_visibility: ["//visibility:private"],
+ visibility: ["//visibility:private"],
}
java_library_static {
@@ -405,6 +409,8 @@
system_modules: "none",
java_version: "1.8",
compile_dex: true,
+ defaults_visibility: ["//visibility:private"],
+ visibility: ["//visibility:public"],
}
java_defaults {
@@ -417,6 +423,7 @@
tag: ".jar",
dest: "android.jar",
},
+ defaults_visibility: ["//frameworks/base/services"],
}
java_library_static {
@@ -516,6 +523,7 @@
"metalava-manual",
],
args: priv_apps,
+ visibility: ["//visibility:private"],
}
java_library_static {
@@ -525,4 +533,5 @@
srcs: [
":hwbinder-stubs-docs",
],
+ visibility: ["//visibility:public"],
}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java
index 35cea3e..6c62426 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java
@@ -26,6 +26,7 @@
import java.util.Collections;
import java.util.Map;
+import java.util.Objects;
/**
* Provides results for AppSearch batch operations which encompass multiple documents.
@@ -180,7 +181,7 @@
public Builder<KeyType, ValueType> setSuccess(
@NonNull KeyType key, @Nullable ValueType result) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
return setResult(key, AppSearchResult.newSuccessfulResult(result));
}
@@ -198,7 +199,7 @@
@AppSearchResult.ResultCode int resultCode,
@Nullable String errorMessage) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
return setResult(key, AppSearchResult.newFailedResult(resultCode, errorMessage));
}
@@ -214,8 +215,8 @@
public Builder<KeyType, ValueType> setResult(
@NonNull KeyType key, @NonNull AppSearchResult<ValueType> result) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(key);
- Preconditions.checkNotNull(result);
+ Objects.requireNonNull(key);
+ Objects.requireNonNull(result);
if (result.isSuccess()) {
mSuccesses.put(key, result.getResultValue());
mFailures.remove(key);
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index 693acf1..f6f5c98 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -54,7 +54,6 @@
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.appsearch.external.localstorage.AppSearchImpl;
@@ -181,10 +180,10 @@
int schemaVersion,
@UserIdInt int userId,
@NonNull IAppSearchResultCallback callback) {
- Preconditions.checkNotNull(packageName);
- Preconditions.checkNotNull(databaseName);
- Preconditions.checkNotNull(schemaBundles);
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(databaseName);
+ Objects.requireNonNull(schemaBundles);
+ Objects.requireNonNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
EXECUTOR.execute(() -> {
@@ -230,9 +229,9 @@
@NonNull String databaseName,
@UserIdInt int userId,
@NonNull IAppSearchResultCallback callback) {
- Preconditions.checkNotNull(packageName);
- Preconditions.checkNotNull(databaseName);
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(databaseName);
+ Objects.requireNonNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
EXECUTOR.execute(() -> {
@@ -257,9 +256,9 @@
@NonNull String databaseName,
@UserIdInt int userId,
@NonNull IAppSearchResultCallback callback) {
- Preconditions.checkNotNull(packageName);
- Preconditions.checkNotNull(databaseName);
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(databaseName);
+ Objects.requireNonNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
EXECUTOR.execute(() -> {
@@ -285,10 +284,10 @@
@UserIdInt int userId,
@ElapsedRealtimeLong long binderCallStartTimeMillis,
@NonNull IAppSearchBatchResultCallback callback) {
- Preconditions.checkNotNull(packageName);
- Preconditions.checkNotNull(databaseName);
- Preconditions.checkNotNull(documentBundles);
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(databaseName);
+ Objects.requireNonNull(documentBundles);
+ Objects.requireNonNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
EXECUTOR.execute(() -> {
@@ -359,11 +358,11 @@
@NonNull Map<String, List<String>> typePropertyPaths,
@UserIdInt int userId,
@NonNull IAppSearchBatchResultCallback callback) {
- Preconditions.checkNotNull(packageName);
- Preconditions.checkNotNull(databaseName);
- Preconditions.checkNotNull(namespace);
- Preconditions.checkNotNull(uris);
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(databaseName);
+ Objects.requireNonNull(namespace);
+ Objects.requireNonNull(uris);
+ Objects.requireNonNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
EXECUTOR.execute(() -> {
@@ -404,11 +403,11 @@
@NonNull Bundle searchSpecBundle,
@UserIdInt int userId,
@NonNull IAppSearchResultCallback callback) {
- Preconditions.checkNotNull(packageName);
- Preconditions.checkNotNull(databaseName);
- Preconditions.checkNotNull(queryExpression);
- Preconditions.checkNotNull(searchSpecBundle);
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(databaseName);
+ Objects.requireNonNull(queryExpression);
+ Objects.requireNonNull(searchSpecBundle);
+ Objects.requireNonNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
EXECUTOR.execute(() -> {
@@ -439,10 +438,10 @@
@NonNull Bundle searchSpecBundle,
@UserIdInt int userId,
@NonNull IAppSearchResultCallback callback) {
- Preconditions.checkNotNull(packageName);
- Preconditions.checkNotNull(queryExpression);
- Preconditions.checkNotNull(searchSpecBundle);
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(queryExpression);
+ Objects.requireNonNull(searchSpecBundle);
+ Objects.requireNonNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
EXECUTOR.execute(() -> {
@@ -471,7 +470,7 @@
long nextPageToken,
@UserIdInt int userId,
@NonNull IAppSearchResultCallback callback) {
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
// TODO(b/162450968) check nextPageToken is being advanced by the same uid as originally
@@ -644,10 +643,10 @@
@NonNull List<String> uris,
@UserIdInt int userId,
@NonNull IAppSearchBatchResultCallback callback) {
- Preconditions.checkNotNull(packageName);
- Preconditions.checkNotNull(databaseName);
- Preconditions.checkNotNull(uris);
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(databaseName);
+ Objects.requireNonNull(uris);
+ Objects.requireNonNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
EXECUTOR.execute(() -> {
@@ -684,11 +683,11 @@
@NonNull Bundle searchSpecBundle,
@UserIdInt int userId,
@NonNull IAppSearchResultCallback callback) {
- Preconditions.checkNotNull(packageName);
- Preconditions.checkNotNull(databaseName);
- Preconditions.checkNotNull(queryExpression);
- Preconditions.checkNotNull(searchSpecBundle);
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(databaseName);
+ Objects.requireNonNull(queryExpression);
+ Objects.requireNonNull(searchSpecBundle);
+ Objects.requireNonNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
EXECUTOR.execute(() -> {
@@ -717,9 +716,9 @@
@NonNull String databaseName,
@UserIdInt int userId,
@NonNull IAppSearchResultCallback callback) {
- Preconditions.checkNotNull(packageName);
- Preconditions.checkNotNull(databaseName);
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(databaseName);
+ Objects.requireNonNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
EXECUTOR.execute(() -> {
@@ -757,7 +756,7 @@
@Override
public void initialize(@UserIdInt int userId, @NonNull IAppSearchResultCallback callback) {
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
EXECUTOR.execute(() -> {
@@ -788,7 +787,7 @@
}
private void verifyCallingPackage(int callingUid, @NonNull String callingPackage) {
- Preconditions.checkNotNull(callingPackage);
+ Objects.requireNonNull(callingPackage);
if (mPackageManagerInternal.getPackageUid(
callingPackage, /*flags=*/ 0, UserHandle.getUserId(callingUid))
!= callingUid) {
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java b/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java
index c1b8294..4de52fb 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java
@@ -35,7 +35,6 @@
import android.util.ArraySet;
import android.util.Log;
-import com.android.internal.util.Preconditions;
import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
import java.util.ArrayList;
@@ -43,6 +42,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
@@ -333,9 +333,9 @@
@NonNull Set<String> schemasNotPlatformSurfaceable,
@NonNull Map<String, List<PackageIdentifier>> schemasPackageAccessible)
throws AppSearchException {
- Preconditions.checkNotNull(prefix);
- Preconditions.checkNotNull(schemasNotPlatformSurfaceable);
- Preconditions.checkNotNull(schemasPackageAccessible);
+ Objects.requireNonNull(prefix);
+ Objects.requireNonNull(schemasNotPlatformSurfaceable);
+ Objects.requireNonNull(schemasPackageAccessible);
// Persist the document
GenericDocument.Builder<?> visibilityDocument =
@@ -383,8 +383,8 @@
/** Checks whether {@code prefixedSchema} can be searched over by the {@code callerUid}. */
public boolean isSchemaSearchableByCaller(
@NonNull String prefix, @NonNull String prefixedSchema, int callerUid) {
- Preconditions.checkNotNull(prefix);
- Preconditions.checkNotNull(prefixedSchema);
+ Objects.requireNonNull(prefix);
+ Objects.requireNonNull(prefixedSchema);
// We compare appIds here rather than direct uids because the package's uid may change based
// on the user that's running.
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java
index 1c04d99..731ab35 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java
@@ -29,7 +29,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
-import com.android.internal.util.Preconditions;
import com.android.server.appsearch.external.localstorage.AppSearchLogger;
import com.android.server.appsearch.external.localstorage.stats.CallStats;
import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
@@ -38,6 +37,7 @@
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
+import java.util.Objects;
import java.util.Random;
/**
@@ -162,15 +162,15 @@
* Westworld constructor
*/
public PlatformLogger(@NonNull Context context, int userId, @NonNull Config config) {
- mContext = Preconditions.checkNotNull(context);
- mConfig = Preconditions.checkNotNull(config);
+ mContext = Objects.requireNonNull(context);
+ mConfig = Objects.requireNonNull(config);
mUserId = userId;
}
/** Logs {@link CallStats}. */
@Override
public void logStats(@NonNull CallStats stats) {
- Preconditions.checkNotNull(stats);
+ Objects.requireNonNull(stats);
synchronized (mLock) {
if (shouldLogForTypeLocked(stats.getCallType())) {
logStatsImplLocked(stats);
@@ -181,7 +181,7 @@
/** Logs {@link PutDocumentStats}. */
@Override
public void logStats(@NonNull PutDocumentStats stats) {
- Preconditions.checkNotNull(stats);
+ Objects.requireNonNull(stats);
synchronized (mLock) {
if (shouldLogForTypeLocked(CallStats.CALL_TYPE_PUT_DOCUMENT)) {
logStatsImplLocked(stats);
@@ -197,7 +197,7 @@
*/
public int removeCachedUidForPackage(@NonNull String packageName) {
// TODO(b/173532925) This needs to be called when we get PACKAGE_REMOVED intent
- Preconditions.checkNotNull(packageName);
+ Objects.requireNonNull(packageName);
synchronized (mLock) {
Integer uid = mPackageUidCacheLocked.remove(packageName);
return uid != null ? uid : Process.INVALID_UID;
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java
index f0de496..6193367 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java
@@ -40,11 +40,11 @@
import androidx.test.core.app.ApplicationProvider;
-import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -81,8 +81,8 @@
private AppSearchSessionShimImpl(
@NonNull AppSearchSession session, @NonNull ExecutorService executor) {
- mAppSearchSession = Preconditions.checkNotNull(session);
- mExecutor = Preconditions.checkNotNull(executor);
+ mAppSearchSession = Objects.requireNonNull(session);
+ mExecutor = Objects.requireNonNull(executor);
}
@Override
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java
index 5042ce0..c35849d 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java
@@ -30,11 +30,11 @@
import androidx.test.core.app.ApplicationProvider;
-import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
+import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -69,8 +69,8 @@
private GlobalSearchSessionShimImpl(
@NonNull GlobalSearchSession session, @NonNull ExecutorService executor) {
- mGlobalSearchSession = Preconditions.checkNotNull(session);
- mExecutor = Preconditions.checkNotNull(executor);
+ mGlobalSearchSession = Objects.requireNonNull(session);
+ mExecutor = Objects.requireNonNull(executor);
}
@NonNull
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/SearchResultsShimImpl.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/SearchResultsShimImpl.java
index 5f26e8c..72078f8 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/SearchResultsShimImpl.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/SearchResultsShimImpl.java
@@ -22,12 +22,12 @@
import android.app.appsearch.SearchResults;
import android.app.appsearch.SearchResultsShim;
-import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -40,8 +40,8 @@
private final SearchResults mSearchResults;
SearchResultsShimImpl(@NonNull SearchResults searchResults, @NonNull Executor executor) {
- mExecutor = Preconditions.checkNotNull(executor);
- mSearchResults = Preconditions.checkNotNull(searchResults);
+ mExecutor = Objects.requireNonNull(executor);
+ mSearchResults = Objects.requireNonNull(searchResults);
}
@NonNull
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 31da201..03d9a96 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -1684,17 +1684,13 @@
}
}
- if ((flags & AlarmManager.FLAG_IDLE_UNTIL) != 0) {
- // Do not support windows for idle-until alarms.
- windowLength = AlarmManager.WINDOW_EXACT;
- }
-
// Snap the window to reasonable limits.
if (windowLength > INTERVAL_DAY) {
Slog.w(TAG, "Window length " + windowLength
+ "ms suspiciously long; limiting to 1 day");
windowLength = INTERVAL_DAY;
- } else if (windowLength > 0 && windowLength < mConstants.MIN_WINDOW) {
+ } else if (windowLength > 0 && windowLength < mConstants.MIN_WINDOW
+ && (flags & FLAG_PRIORITIZE) == 0) {
if (CompatChanges.isChangeEnabled(AlarmManager.ENFORCE_MINIMUM_WINDOW_ON_INEXACT_ALARMS,
callingPackage, UserHandle.getUserHandleForUid(callingUid))) {
Slog.w(TAG, "Window length " + windowLength + "ms too short; expanding to "
@@ -1741,7 +1737,7 @@
final long triggerElapsed = (nominalTrigger > minTrigger) ? nominalTrigger : minTrigger;
final long maxElapsed;
- if (windowLength == AlarmManager.WINDOW_EXACT) {
+ if (windowLength == 0) {
maxElapsed = triggerElapsed;
} else if (windowLength < 0) {
maxElapsed = maxTriggerTime(nowElapsed, triggerElapsed, interval);
@@ -2145,17 +2141,63 @@
+ " does not belong to the calling uid " + callingUid);
}
- final boolean allowWhileIdle = (flags & FLAG_ALLOW_WHILE_IDLE) != 0;
- final boolean exact = (windowLength == AlarmManager.WINDOW_EXACT);
+ // Repeating alarms must use PendingIntent, not direct listener
+ if (interval != 0 && directReceiver != null) {
+ throw new IllegalArgumentException("Repeating alarms cannot use AlarmReceivers");
+ }
- // make sure the caller is allowed to use the requested kind of alarm, and also
+ if (workSource != null) {
+ getContext().enforcePermission(
+ android.Manifest.permission.UPDATE_DEVICE_STATS,
+ Binder.getCallingPid(), callingUid, "AlarmManager.set");
+ }
+
+ if ((flags & AlarmManager.FLAG_IDLE_UNTIL) != 0) {
+ // Only the system can use FLAG_IDLE_UNTIL -- this is used to tell the alarm
+ // manager when to come out of idle mode, which is only for DeviceIdleController.
+ if (callingUid != Process.SYSTEM_UID) {
+ // TODO (b/169463012): Throw instead of tolerating this mistake.
+ flags &= ~AlarmManager.FLAG_IDLE_UNTIL;
+ } else {
+ // Do not support windows for idle-until alarms.
+ windowLength = 0;
+ }
+ }
+
+ // Remove flags reserved for the service, we will apply those later as appropriate.
+ flags &= ~(FLAG_WAKE_FROM_IDLE | FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED
+ | FLAG_ALLOW_WHILE_IDLE_COMPAT);
+
+ // If this alarm is for an alarm clock, then it must be exact and we will
+ // use it to wake early from idle if needed.
+ if (alarmClock != null) {
+ flags |= FLAG_WAKE_FROM_IDLE;
+ windowLength = 0;
+
+ // If the caller is a core system component or on the user's allowlist, and not calling
+ // to do work on behalf of someone else, then always set ALLOW_WHILE_IDLE_UNRESTRICTED.
+ // This means we will allow these alarms to go off as normal even while idle, with no
+ // timing restrictions.
+ } else if (workSource == null && (UserHandle.isCore(callingUid)
+ || UserHandle.isSameApp(callingUid, mSystemUiUid)
+ || ((mAppStateTracker != null)
+ && mAppStateTracker.isUidPowerSaveUserExempt(callingUid)))) {
+ flags |= FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
+ flags &= ~(FLAG_ALLOW_WHILE_IDLE | FLAG_PRIORITIZE);
+ }
+
+ final boolean allowWhileIdle = (flags & FLAG_ALLOW_WHILE_IDLE) != 0;
+ final boolean exact = (windowLength == 0);
+
+ // Make sure the caller is allowed to use the requested kind of alarm, and also
// decide what quota and broadcast options to use.
Bundle idleOptions = null;
if ((flags & FLAG_PRIORITIZE) != 0) {
getContext().enforcePermission(
Manifest.permission.SCHEDULE_PRIORITIZED_ALARM,
Binder.getCallingPid(), callingUid, "AlarmManager.setPrioritized");
- flags &= ~(FLAG_ALLOW_WHILE_IDLE | FLAG_ALLOW_WHILE_IDLE_COMPAT);
+ // The API doesn't allow using both together.
+ flags &= ~FLAG_ALLOW_WHILE_IDLE;
} else if (exact || allowWhileIdle) {
final boolean needsPermission;
boolean lowerQuota;
@@ -2193,55 +2235,11 @@
}
}
- // Repeating alarms must use PendingIntent, not direct listener
- if (interval != 0) {
- if (directReceiver != null) {
- throw new IllegalArgumentException(
- "Repeating alarms cannot use AlarmReceivers");
- }
- }
-
- if (workSource != null) {
- getContext().enforcePermission(
- android.Manifest.permission.UPDATE_DEVICE_STATS,
- Binder.getCallingPid(), callingUid, "AlarmManager.set");
- }
-
- // No incoming callers can request either WAKE_FROM_IDLE or
- // ALLOW_WHILE_IDLE_UNRESTRICTED -- we will apply those later as appropriate.
- flags &= ~(FLAG_WAKE_FROM_IDLE | FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED);
-
- // Only the system can use FLAG_IDLE_UNTIL -- this is used to tell the alarm
- // manager when to come out of idle mode, which is only for DeviceIdleController.
- if (callingUid != Process.SYSTEM_UID) {
- flags &= ~AlarmManager.FLAG_IDLE_UNTIL;
- }
-
// If this is an exact time alarm, then it can't be batched with other alarms.
- if (windowLength == AlarmManager.WINDOW_EXACT) {
+ if (exact) {
flags |= AlarmManager.FLAG_STANDALONE;
}
- // If this alarm is for an alarm clock, then it must be standalone and we will
- // use it to wake early from idle if needed.
- if (alarmClock != null) {
- flags |= FLAG_WAKE_FROM_IDLE | AlarmManager.FLAG_STANDALONE;
-
- // If the caller is a core system component or on the user's whitelist, and not calling
- // to do work on behalf of someone else, then always set ALLOW_WHILE_IDLE_UNRESTRICTED.
- // This means we will allow these alarms to go off as normal even while idle, with no
- // timing restrictions.
- } else if (workSource == null && (UserHandle.isCore(callingUid)
- || UserHandle.isSameApp(callingUid, mSystemUiUid)
- || ((mAppStateTracker != null)
- && mAppStateTracker.isUidPowerSaveUserExempt(callingUid)))) {
- flags |= FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
- flags &= ~FLAG_ALLOW_WHILE_IDLE;
- flags &= ~FLAG_ALLOW_WHILE_IDLE_COMPAT;
- flags &= ~FLAG_PRIORITIZE;
- idleOptions = null;
- }
-
setImpl(type, triggerAtTime, windowLength, interval, operation, directReceiver,
listenerTag, flags, workSource, alarmClock, callingUid, callingPackage,
idleOptions);
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java
index c37d2c3..9b1b066 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java
@@ -16,7 +16,6 @@
package com.android.server.alarm;
-import static com.android.server.alarm.AlarmManagerService.TAG;
import static com.android.server.alarm.AlarmManagerService.dumpAlarmList;
import static com.android.server.alarm.AlarmManagerService.isTimeTickAlarm;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 667f5ab..1815661 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -2234,7 +2234,8 @@
}
/** Returns true if both the calling and source users for the job are started. */
- private boolean areUsersStartedLocked(final JobStatus job) {
+ @GuardedBy("mLock")
+ public boolean areUsersStartedLocked(final JobStatus job) {
boolean sourceStarted = ArrayUtils.contains(mStartedUsers, job.getSourceUserId());
if (job.getUserId() == job.getSourceUserId()) {
return sourceStarted;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java
index 999c53f..12d9c7f 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java
@@ -34,6 +34,7 @@
import android.util.SparseArrayMap;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.GuardedBy;
import com.android.server.job.JobSchedulerService;
import java.util.Objects;
@@ -58,13 +59,28 @@
return;
}
switch (action) {
+ case Intent.ACTION_PACKAGE_ADDED:
+ if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ // Only do this for app updates since new installs won't have any jobs
+ // scheduled.
+ final Uri uri = intent.getData();
+ final String pkg = uri != null ? uri.getSchemeSpecificPart() : null;
+ if (pkg != null) {
+ final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ final int userId = UserHandle.getUserId(pkgUid);
+ updateComponentStateForPackage(userId, pkg);
+ }
+ }
+ break;
case Intent.ACTION_PACKAGE_CHANGED:
final Uri uri = intent.getData();
final String pkg = uri != null ? uri.getSchemeSpecificPart() : null;
final String[] changedComponents = intent.getStringArrayExtra(
Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
if (pkg != null && changedComponents != null && changedComponents.length > 0) {
- updateComponentStateForPackage(pkg);
+ final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ final int userId = UserHandle.getUserId(pkgUid);
+ updateComponentStateForPackage(userId, pkg);
}
break;
case Intent.ACTION_USER_UNLOCKED:
@@ -86,6 +102,7 @@
super(service);
final IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme("package");
mContext.registerReceiverAsUser(
@@ -99,6 +116,7 @@
}
@Override
+ @GuardedBy("mLock")
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
updateComponentEnabledStateLocked(jobStatus);
}
@@ -108,30 +126,53 @@
boolean forUpdate) {
}
+ @Override
+ @GuardedBy("mLock")
+ public void onAppRemovedLocked(String packageName, int uid) {
+ clearComponentsForPackageLocked(UserHandle.getUserId(uid), packageName);
+ }
+
+ @Override
+ @GuardedBy("mLock")
+ public void onUserRemovedLocked(int userId) {
+ mServiceInfoCache.delete(userId);
+ }
+
@Nullable
- private ServiceInfo getServiceInfo(JobStatus jobStatus) {
+ @GuardedBy("mLock")
+ private ServiceInfo getServiceInfoLocked(JobStatus jobStatus) {
final ComponentName service = jobStatus.getServiceComponent();
final int userId = jobStatus.getUserId();
- ServiceInfo si = mServiceInfoCache.get(userId, service);
- if (si == null) {
- try {
- // createContextAsUser may potentially be expensive
- // TODO: cache user context or improve ContextImpl implementation if this becomes
- // a problem
- si = mContext.createContextAsUser(UserHandle.of(userId), 0)
- .getPackageManager()
- .getServiceInfo(service, PackageManager.MATCH_DIRECT_BOOT_AUTO);
- } catch (NameNotFoundException e) {
- Slog.e(TAG, "Job exists for non-existent package: " + service.getPackageName());
- return null;
- }
- mServiceInfoCache.add(userId, service, si);
+ if (mServiceInfoCache.contains(userId, service)) {
+ // Return whatever is in the cache, even if it's null. When something changes, we
+ // clear the cache.
+ return mServiceInfoCache.get(userId, service);
}
+
+ ServiceInfo si;
+ try {
+ // createContextAsUser may potentially be expensive
+ // TODO: cache user context or improve ContextImpl implementation if this becomes
+ // a problem
+ si = mContext.createContextAsUser(UserHandle.of(userId), 0)
+ .getPackageManager()
+ .getServiceInfo(service, PackageManager.MATCH_DIRECT_BOOT_AUTO);
+ } catch (NameNotFoundException e) {
+ if (mService.areUsersStartedLocked(jobStatus)) {
+ // User is fully unlocked but PM still says the package doesn't exist.
+ Slog.e(TAG, "Job exists for non-existent package: " + service.getPackageName());
+ }
+ // Write null to the cache so we don't keep querying PM.
+ si = null;
+ }
+ mServiceInfoCache.add(userId, service, si);
+
return si;
}
+ @GuardedBy("mLock")
private boolean updateComponentEnabledStateLocked(JobStatus jobStatus) {
- final ServiceInfo service = getServiceInfo(jobStatus);
+ final ServiceInfo service = getServiceInfoLocked(jobStatus);
if (DEBUG && service == null) {
Slog.v(TAG, jobStatus.toShortString() + " component not present");
@@ -141,20 +182,26 @@
return !Objects.equals(ogService, service);
}
- private void updateComponentStateForPackage(final String pkg) {
- synchronized (mLock) {
- for (int u = mServiceInfoCache.numMaps() - 1; u >= 0; --u) {
- final int userId = mServiceInfoCache.keyAt(u);
-
- for (int c = mServiceInfoCache.numElementsForKey(userId) - 1; c >= 0; --c) {
- final ComponentName cn = mServiceInfoCache.keyAt(u, c);
- if (cn.getPackageName().equals(pkg)) {
- mServiceInfoCache.delete(userId, cn);
- }
- }
+ @GuardedBy("mLock")
+ private void clearComponentsForPackageLocked(final int userId, final String pkg) {
+ final int uIdx = mServiceInfoCache.indexOfKey(userId);
+ for (int c = mServiceInfoCache.numElementsForKey(userId) - 1; c >= 0; --c) {
+ final ComponentName cn = mServiceInfoCache.keyAt(uIdx, c);
+ if (cn.getPackageName().equals(pkg)) {
+ mServiceInfoCache.delete(userId, cn);
}
- updateComponentStatesLocked(
- jobStatus -> jobStatus.getServiceComponent().getPackageName().equals(pkg));
+ }
+ }
+
+ private void updateComponentStateForPackage(final int userId, final String pkg) {
+ synchronized (mLock) {
+ clearComponentsForPackageLocked(userId, pkg);
+ updateComponentStatesLocked(jobStatus -> {
+ // Using user ID instead of source user ID because the service will run under the
+ // user ID, not source user ID.
+ return jobStatus.getUserId() == userId
+ && jobStatus.getServiceComponent().getPackageName().equals(pkg);
+ });
}
}
@@ -169,6 +216,7 @@
}
}
+ @GuardedBy("mLock")
private void updateComponentStatesLocked(@NonNull Predicate<JobStatus> filter) {
mComponentStateUpdateFunctor.reset();
mService.getJobStore().forEachJob(filter, mComponentStateUpdateFunctor);
@@ -178,24 +226,40 @@
}
final class ComponentStateUpdateFunctor implements Consumer<JobStatus> {
+ @GuardedBy("mLock")
boolean mChanged;
@Override
+ @GuardedBy("mLock")
public void accept(JobStatus jobStatus) {
mChanged |= updateComponentEnabledStateLocked(jobStatus);
}
+ @GuardedBy("mLock")
private void reset() {
mChanged = false;
}
}
@Override
+ @GuardedBy("mLock")
public void dumpControllerStateLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate) {
-
+ for (int u = 0; u < mServiceInfoCache.numMaps(); ++u) {
+ final int userId = mServiceInfoCache.keyAt(u);
+ for (int p = 0; p < mServiceInfoCache.numElementsForKey(userId); ++p) {
+ final ComponentName componentName = mServiceInfoCache.keyAt(u, p);
+ pw.print(userId);
+ pw.print("-");
+ pw.print(componentName);
+ pw.print(": ");
+ pw.print(mServiceInfoCache.valueAt(u, p));
+ pw.println();
+ }
+ }
}
@Override
+ @GuardedBy("mLock")
public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
Predicate<JobStatus> predicate) {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index f7b4cdc..5b978e5 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -2321,7 +2321,7 @@
field public static final String SYSTEM_CONFIG_SERVICE = "system_config";
field public static final String SYSTEM_UPDATE_SERVICE = "system_update";
field public static final String TETHERING_SERVICE = "tethering";
- field public static final String TRANSLATION_MANAGER_SERVICE = "transformer";
+ field public static final String TRANSLATION_MANAGER_SERVICE = "translation";
field public static final String UI_TRANSLATION_SERVICE = "ui_translation";
field public static final String VR_SERVICE = "vrmanager";
field public static final String WIFI_NL80211_SERVICE = "wifinl80211";
@@ -7298,10 +7298,6 @@
package android.net {
- public class DnsResolverServiceManager {
- method @NonNull @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public static android.os.IBinder getService(@NonNull android.content.Context);
- }
-
public class EthernetManager {
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull java.util.concurrent.Executor, @NonNull android.net.EthernetManager.TetheredInterfaceCallback);
}
@@ -7861,7 +7857,7 @@
method @Nullable public android.net.wifi.nl80211.WifiNl80211Manager.TxPacketCounters getTxPacketCounters(@NonNull String);
method @Nullable public static android.net.wifi.nl80211.WifiNl80211Manager.OemSecurityType parseOemSecurityTypeElement(int, int, @NonNull byte[]);
method @Deprecated public boolean registerApCallback(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.nl80211.WifiNl80211Manager.SoftApCallback);
- method public boolean registerCountryCodeChangeListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.nl80211.WifiNl80211Manager.CountryCodeChangeListener);
+ method public boolean registerCountryCodeChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.nl80211.WifiNl80211Manager.CountryCodeChangedListener);
method public void sendMgmtFrame(@NonNull String, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.nl80211.WifiNl80211Manager.SendMgmtFrameCallback);
method public void setOnServiceDeadCallback(@NonNull Runnable);
method public boolean setupInterfaceForClientMode(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.nl80211.WifiNl80211Manager.ScanEventCallback, @NonNull android.net.wifi.nl80211.WifiNl80211Manager.ScanEventCallback);
@@ -7874,7 +7870,7 @@
method public boolean tearDownClientInterface(@NonNull String);
method public boolean tearDownInterfaces();
method public boolean tearDownSoftApInterface(@NonNull String);
- method public void unregisterCountryCodeChangeListener(@NonNull android.net.wifi.nl80211.WifiNl80211Manager.CountryCodeChangeListener);
+ method public void unregisterCountryCodeChangedListener(@NonNull android.net.wifi.nl80211.WifiNl80211Manager.CountryCodeChangedListener);
field public static final String SCANNING_PARAM_ENABLE_6GHZ_RNR = "android.net.wifi.nl80211.SCANNING_PARAM_ENABLE_6GHZ_RNR";
field public static final int SCAN_TYPE_PNO_SCAN = 1; // 0x1
field public static final int SCAN_TYPE_SINGLE_SCAN = 0; // 0x0
@@ -7885,8 +7881,8 @@
field public static final int SEND_MGMT_FRAME_ERROR_UNKNOWN = 1; // 0x1
}
- public static interface WifiNl80211Manager.CountryCodeChangeListener {
- method public void onChanged(@NonNull String);
+ public static interface WifiNl80211Manager.CountryCodeChangedListener {
+ method public void onCountryCodeChanged(@NonNull String);
}
public static class WifiNl80211Manager.OemSecurityType {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index a77bf32..e449728 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1575,6 +1575,10 @@
method public static void setServiceForTest(@Nullable android.os.IBinder);
}
+ public class NetworkWatchlistManager {
+ method @Nullable public byte[] getWatchlistConfigHash();
+ }
+
public class TrafficStats {
method public static long getLoopbackRxBytes();
method public static long getLoopbackRxPackets();
@@ -2010,6 +2014,7 @@
public final class PermissionManager {
method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.permission.PermGroupUsage> getIndicatorAppOpUsageData();
+ method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.permission.PermGroupUsage> getIndicatorAppOpUsageData(boolean);
method @NonNull public android.content.AttributionSource registerAttributionSource(@NonNull android.content.AttributionSource);
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index df9530f..1cb46b1 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -6475,7 +6475,7 @@
historicalDiscreteAccesses.add(other.mDiscreteAccesses.get(i++));
}
}
- mDiscreteAccesses = historicalDiscreteAccesses;
+ mDiscreteAccesses = deduplicateDiscreteEvents(historicalDiscreteAccesses);
}
private void increaseAccessCount(@UidState int uidState, @OpFlags int flags,
@@ -6996,7 +6996,7 @@
}
result.add(entry);
}
- return result;
+ return deduplicateDiscreteEvents(result);
}
/**
@@ -9819,4 +9819,52 @@
}
}
}
+
+ private static List<AttributedOpEntry> deduplicateDiscreteEvents(List<AttributedOpEntry> list) {
+ int n = list.size();
+ int i = 0;
+ for (int j = 0, k = 0; j < n; i++, j = k) {
+ long currentAccessTime = list.get(j).getLastAccessTime(OP_FLAGS_ALL);
+ k = j + 1;
+ while(k < n && list.get(k).getLastAccessTime(OP_FLAGS_ALL) == currentAccessTime) {
+ k++;
+ }
+ list.set(i, mergeAttributedOpEntries(list.subList(j, k)));
+ }
+ for (; i < n; i++) {
+ list.remove(list.size() - 1);
+ }
+ return list;
+ }
+
+ private static AttributedOpEntry mergeAttributedOpEntries(List<AttributedOpEntry> opEntries) {
+ if (opEntries.size() == 1) {
+ return opEntries.get(0);
+ }
+ LongSparseArray<AppOpsManager.NoteOpEvent> accessEvents = new LongSparseArray<>();
+ LongSparseArray<AppOpsManager.NoteOpEvent> rejectEvents = new LongSparseArray<>();
+ int opCount = opEntries.size();
+ for (int i = 0; i < opCount; i++) {
+ AttributedOpEntry a = opEntries.get(i);
+ ArraySet<Long> keys = a.collectKeys();
+ final int keyCount = keys.size();
+ for (int k = 0; k < keyCount; k++) {
+ final long key = keys.valueAt(k);
+
+ final int uidState = extractUidStateFromKey(key);
+ final int flags = extractFlagsFromKey(key);
+
+ NoteOpEvent access = a.getLastAccessEvent(uidState, uidState, flags);
+ NoteOpEvent reject = a.getLastRejectEvent(uidState, uidState, flags);
+
+ if (access != null) {
+ accessEvents.append(key, access);
+ }
+ if (reject != null) {
+ rejectEvents.append(key, reject);
+ }
+ }
+ }
+ return new AttributedOpEntry(opEntries.get(0).mOp, false, accessEvents, rejectEvents);
+ }
}
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index e83557c..4f7c684 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -190,4 +190,18 @@
* Called from SystemUI when it shows the AoD UI.
*/
oneway void setInAmbientMode(boolean inAmbientMode, long animationDuration);
+
+ /**
+ * Called from SystemUI when the device is waking up.
+ *
+ * @hide
+ */
+ oneway void notifyWakingUp(int x, int y, in Bundle extras);
+
+ /**
+ * Called from SystemUI when the device is going to sleep.
+ *
+ * @hide
+ */
+ void notifyGoingToSleep(int x, int y, in Bundle extras);
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 6a71c92..8d332ab 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -190,6 +190,30 @@
public static final String COMMAND_DROP = "android.home.drop";
/**
+ * Command for {@link #sendWallpaperCommand}: reported by System UI when the device is waking
+ * up. The x and y arguments are a location (possibly very roughly) corresponding to the action
+ * that caused the device to wake up. For example, if the power button was pressed, this will be
+ * the location on the screen nearest the power button.
+ *
+ * If the location is unknown or not applicable, x and y will be -1.
+ *
+ * @hide
+ */
+ public static final String COMMAND_WAKING_UP = "android.wallpaper.wakingup";
+
+ /**
+ * Command for {@link #sendWallpaperCommand}: reported by System UI when the device is going to
+ * sleep. The x and y arguments are a location (possibly very roughly) corresponding to the
+ * action that caused the device to go to sleep. For example, if the power button was pressed,
+ * this will be the location on the screen nearest the power button.
+ *
+ * If the location is unknown or not applicable, x and y will be -1.
+ *
+ * @hide
+ */
+ public static final String COMMAND_GOING_TO_SLEEP = "android.wallpaper.goingtosleep";
+
+ /**
* Command for {@link #sendWallpaperCommand}: reported when the wallpaper that was already
* set is re-applied by the user.
* @hide
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index a72877e..fe81df0 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -320,6 +320,15 @@
}
/**
+ * Set the host's interaction handler.
+ *
+ * @hide
+ */
+ public void setInteractionHandler(InteractionHandler interactionHandler) {
+ mInteractionHandler = interactionHandler;
+ }
+
+ /**
* Gets a list of all the appWidgetIds that are bound to the current host
*/
public int[] getAppWidgetIds() {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 318913f..a88c9ed 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4705,10 +4705,9 @@
* @hide
* @see #getSystemService(String)
*/
- // TODO(b/176208267): change it back to translation before S release.
@SystemApi
@SuppressLint("ServiceName")
- public static final String TRANSLATION_MANAGER_SERVICE = "transformer";
+ public static final String TRANSLATION_MANAGER_SERVICE = "translation";
/**
* Official published name of the translation service which supports ui translation function.
diff --git a/core/java/android/content/pm/PackagePartitions.java b/core/java/android/content/pm/PackagePartitions.java
index 98a20f7..52ee4de 100644
--- a/core/java/android/content/pm/PackagePartitions.java
+++ b/core/java/android/content/pm/PackagePartitions.java
@@ -47,7 +47,7 @@
public static final int PARTITION_PRODUCT = 4;
public static final int PARTITION_SYSTEM_EXT = 5;
- @IntDef(flag = true, prefix = { "PARTITION_" }, value = {
+ @IntDef(prefix = { "PARTITION_" }, value = {
PARTITION_SYSTEM,
PARTITION_VENDOR,
PARTITION_ODM,
diff --git a/core/java/android/content/pm/parsing/component/ParsedAttribution.java b/core/java/android/content/pm/parsing/component/ParsedAttribution.java
index 4ec2e73..3a4aae1 100644
--- a/core/java/android/content/pm/parsing/component/ParsedAttribution.java
+++ b/core/java/android/content/pm/parsing/component/ParsedAttribution.java
@@ -40,7 +40,7 @@
public static final int MAX_ATTRIBUTION_TAG_LEN = 50;
/** Maximum amount of attributions per package */
- private static final int MAX_NUM_ATTRIBUTIONS = 10000;
+ private static final int MAX_NUM_ATTRIBUTIONS = 1000;
/** Tag of the attribution */
public final @NonNull String tag;
@@ -100,7 +100,7 @@
- // Code below generated by codegen v1.0.23.
+ // Code below generated by codegen v1.0.22.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -215,8 +215,8 @@
};
@DataClass.Generated(
- time = 1618351459610L,
- codegenVersion = "1.0.23",
+ time = 1607463855175L,
+ codegenVersion = "1.0.22",
sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedAttribution.java",
inputSignatures = "public static final int MAX_ATTRIBUTION_TAG_LEN\nprivate static final int MAX_NUM_ATTRIBUTIONS\npublic final @android.annotation.NonNull java.lang.String tag\npublic final @android.annotation.StringRes int label\npublic final @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\npublic static boolean isCombinationValid(java.util.List<android.content.pm.parsing.component.ParsedAttribution>)\nclass ParsedAttribution extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=false)")
@Deprecated
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 4ee5383..f03da7c 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -718,7 +718,7 @@
public final void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
@NonNull EditorInfo editorInfo, boolean restarting,
@NonNull IBinder startInputToken) {
- mPrivOps.reportStartInput(startInputToken);
+ mPrivOps.reportStartInputAsync(startInputToken);
if (restarting) {
restartInput(inputConnection, editorInfo);
diff --git a/core/java/android/net/DnsResolverServiceManager.java b/core/java/android/net/DnsResolverServiceManager.java
deleted file mode 100644
index 1597322..0000000
--- a/core/java/android/net/DnsResolverServiceManager.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net;
-
-import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
-import android.content.Context;
-import android.os.IBinder;
-import android.os.ServiceManager;
-
-import java.util.Objects;
-
-/**
- * Provides a way to obtain the DnsResolver binder objects.
- *
- * @hide
- */
-@SystemApi
-public class DnsResolverServiceManager {
- /**
- * Name to retrieve a {@link android.net.IDnsResolver} IBinder.
- */
- private static final String DNS_RESOLVER_SERVICE = "dnsresolver";
-
- private DnsResolverServiceManager() {}
-
- /**
- * Get an {@link IBinder} representing the DnsResolver stable AIDL interface
- *
- * @param context the context for permission check.
- * @return {@link android.net.IDnsResolver} IBinder.
- */
- @NonNull
- @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
- public static IBinder getService(@NonNull final Context context) {
- Objects.requireNonNull(context);
- context.enforceCallingOrSelfPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- "DnsResolverServiceManager");
- try {
- return ServiceManager.getServiceOrThrow(DNS_RESOLVER_SERVICE);
- } catch (ServiceManager.ServiceNotFoundException e) {
- // Catch ServiceManager#ServiceNotFoundException and rethrow IllegalStateException
- // because ServiceManager#ServiceNotFoundException is @hide so that it can't be listed
- // on the system api. Thus, rethrow IllegalStateException if dns resolver service cannot
- // be found.
- throw new IllegalStateException("Cannot find dns resolver service.");
- }
- }
-}
diff --git a/core/java/android/net/NetworkWatchlistManager.java b/core/java/android/net/NetworkWatchlistManager.java
index 8f6510e..da01dcb 100644
--- a/core/java/android/net/NetworkWatchlistManager.java
+++ b/core/java/android/net/NetworkWatchlistManager.java
@@ -19,6 +19,7 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -31,6 +32,7 @@
* Class that manage network watchlist in system.
* @hide
*/
+@TestApi
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@SystemService(Context.NETWORK_WATCHLIST_SERVICE)
public class NetworkWatchlistManager {
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index 16d041a..d026e95 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -34,6 +34,9 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
/**
* Java proxy for a native IBinder object.
@@ -262,27 +265,45 @@
Log.e(Binder.TAG, "RemoteException while disabling app freezer");
}
- for (WeakReference<BinderProxy> weakRef : proxiesToQuery) {
- BinderProxy bp = weakRef.get();
- String key;
- if (bp == null) {
- key = "<cleared weak-ref>";
- } else {
- try {
- key = bp.getInterfaceDescriptor();
- if ((key == null || key.isEmpty()) && !bp.isBinderAlive()) {
- key = "<proxy to dead node>";
+ // We run the dump on a separate thread, because there are known cases where
+ // a process overrides getInterfaceDescriptor() and somehow blocks on it, causing
+ // the calling thread (usually AMS) to hit the watchdog.
+ // Do the dumping on a separate thread instead, and give up after a while.
+ ExecutorService executorService = Executors.newSingleThreadExecutor();
+ executorService.submit(() -> {
+ for (WeakReference<BinderProxy> weakRef : proxiesToQuery) {
+ BinderProxy bp = weakRef.get();
+ String key;
+ if (bp == null) {
+ key = "<cleared weak-ref>";
+ } else {
+ try {
+ key = bp.getInterfaceDescriptor();
+ if ((key == null || key.isEmpty()) && !bp.isBinderAlive()) {
+ key = "<proxy to dead node>";
+ }
+ } catch (Throwable t) {
+ key = "<exception during getDescriptor>";
}
- } catch (Throwable t) {
- key = "<exception during getDescriptor>";
+ }
+ Integer i = counts.get(key);
+ if (i == null) {
+ counts.put(key, 1);
+ } else {
+ counts.put(key, i + 1);
}
}
- Integer i = counts.get(key);
- if (i == null) {
- counts.put(key, 1);
- } else {
- counts.put(key, i + 1);
+ });
+
+ try {
+ executorService.shutdown();
+ boolean dumpDone = executorService.awaitTermination(20, TimeUnit.SECONDS);
+ if (!dumpDone) {
+ Log.e(Binder.TAG, "Failed to complete binder proxy dump,"
+ + " dumping what we have so far.");
}
+ } catch (InterruptedException e) {
+ // Ignore
}
try {
ActivityManager.getService().enableAppFreezer(true);
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 1a40f06..17c90d6 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -886,6 +886,24 @@
}
/**
+ * @param micMuted whether to consider the microphone muted when retrieving audio ops
+ * @return A list of permission groups currently or recently used by all apps by all users in
+ * the current profile group.
+ *
+ * @hide
+ */
+ @TestApi
+ @NonNull
+ @RequiresPermission(Manifest.permission.GET_APP_OPS_STATS)
+ public List<PermGroupUsage> getIndicatorAppOpUsageData(boolean micMuted) {
+ // Lazily initialize the usage helper
+ if (mUsageHelper == null) {
+ mUsageHelper = new PermissionUsageHelper(mContext);
+ }
+ return mUsageHelper.getOpUsageData(micMuted);
+ }
+
+ /**
* Determine if a package should be shown in indicators. Only a select few roles, and the
* system app itself, are hidden. These values are updated at most every 15 seconds.
* @hide
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index d89c29a..87fb611 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -37,6 +37,7 @@
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.TypedArray;
+import android.graphics.BLASTBufferQueue;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
@@ -208,8 +209,8 @@
int mCurHeight;
float mZoom = 0f;
int mWindowFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
- int mWindowPrivateFlags =
- WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS;
+ int mWindowPrivateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS
+ | WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;
int mCurWindowFlags = mWindowFlags;
int mCurWindowPrivateFlags = mWindowPrivateFlags;
Rect mPreviewSurfacePosition;
@@ -253,6 +254,7 @@
private int mDisplayState;
SurfaceControl mSurfaceControl = new SurfaceControl();
+ BLASTBufferQueue mBlastBufferQueue;
final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() {
{
@@ -974,7 +976,14 @@
View.VISIBLE, 0, -1, mWinFrames, mMergedConfiguration, mSurfaceControl,
mInsetsState, mTempControls, mSurfaceSize);
if (mSurfaceControl.isValid()) {
- mSurfaceHolder.mSurface.copyFrom(mSurfaceControl);
+ Surface blastSurface = getOrCreateBLASTSurface(mSurfaceSize.x,
+ mSurfaceSize.y, mFormat);
+ // If blastSurface == null that means it hasn't changed since the last
+ // time we called. In this situation, avoid calling transferFrom as we
+ // would then inc the generation ID and cause EGL resources to be recreated.
+ if (blastSurface != null) {
+ mSurfaceHolder.mSurface.transferFrom(blastSurface);
+ }
}
if (!mLastSurfaceSize.equals(mSurfaceSize)) {
mLastSurfaceSize.set(mSurfaceSize.x, mSurfaceSize.y);
@@ -1455,13 +1464,12 @@
return;
}
Surface surface = mSurfaceHolder.getSurface();
- boolean widthIsLarger =
- mSurfaceControl.getWidth() > mSurfaceControl.getHeight();
- int smaller = widthIsLarger ? mSurfaceControl.getWidth()
- : mSurfaceControl.getHeight();
+ boolean widthIsLarger = mSurfaceSize.x > mSurfaceSize.y;
+ int smaller = widthIsLarger ? mSurfaceSize.x
+ : mSurfaceSize.y;
float ratio = (float) MIN_BITMAP_SCREENSHOT_WIDTH / (float) smaller;
- int width = (int) (ratio * mSurfaceControl.getWidth());
- int height = (int) (ratio * mSurfaceControl.getHeight());
+ int width = (int) (ratio * mSurfaceSize.x);
+ int height = (int) (ratio * mSurfaceSize.y);
if (width <= 0 || height <= 0) {
Log.e(TAG, "wrong width and height values of bitmap " + width + " " + height);
return;
@@ -1842,6 +1850,21 @@
public void onDisplayAdded(int displayId) {
}
};
+
+ private Surface getOrCreateBLASTSurface(int width, int height, int format) {
+ Surface ret = null;
+ if (mBlastBufferQueue == null) {
+ mBlastBufferQueue = new BLASTBufferQueue("Wallpaper", mSurfaceControl, width,
+ height, format);
+ // We only return the Surface the first time, as otherwise
+ // it hasn't changed and there is no need to update.
+ ret = mBlastBufferQueue.createSurface();
+ } else {
+ mBlastBufferQueue.update(mSurfaceControl, width, height, format);
+ }
+
+ return ret;
+ }
}
private boolean isValid(RectF area) {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 21f75d4..2c81e89 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -35,6 +35,7 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.Bitmap;
import android.graphics.ColorSpace;
+import android.graphics.GraphicBuffer;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Point;
@@ -188,6 +189,10 @@
IBinder displayToken, int mode);
private static native void nativeReparent(long transactionObj, long nativeObject,
long newParentNativeObject);
+ private static native void nativeSetBuffer(long transactionObj, long nativeObject,
+ GraphicBuffer buffer);
+ private static native void nativeSetColorSpace(long transactionObj, long nativeObject,
+ int colorSpace);
private static native void nativeOverrideHdrTypes(IBinder displayToken, int[] modes);
@@ -3362,6 +3367,31 @@
return this;
}
+ /**
+ * Set a buffer for a SurfaceControl. This can only be used for SurfaceControls that were
+ * created as type {@link #FX_SURFACE_BLAST}
+ *
+ * @hide
+ */
+ public Transaction setBuffer(SurfaceControl sc, GraphicBuffer buffer) {
+ checkPreconditions(sc);
+ nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer);
+ return this;
+ }
+
+ /**
+ * Set the color space for the SurfaceControl. The supported color spaces are SRGB
+ * and Display P3, other color spaces will be treated as SRGB. This can only be used for
+ * SurfaceControls that were created as type {@link #FX_SURFACE_BLAST}
+ *
+ * @hide
+ */
+ public Transaction setColorSpace(SurfaceControl sc, ColorSpace colorSpace) {
+ checkPreconditions(sc);
+ nativeSetColorSpace(mNativeObject, sc.mNativeObject, colorSpace.getId());
+ return this;
+ }
+
/**
* Merge the other transaction into this transaction, clearing the
* other transaction as if it had been applied.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 76eb882..be8e519 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -9309,11 +9309,11 @@
* Handles an inbound request for scroll capture from the system. A search will be
* dispatched through the view tree to locate scrolling content.
* <p>
- * A call to {@link IScrollCaptureCallbacks#onScrollCaptureResponse(ScrollCaptureResponse)}
- * will follow.
+ * A call to
+ * {@link IScrollCaptureResponseListener#onScrollCaptureResponse} will follow.
*
* @param listener to receive responses
- * @see ScrollCaptureTargetSelector
+ * @see ScrollCaptureSearchResults
*/
public void handleScrollCaptureRequest(@NonNull IScrollCaptureResponseListener listener) {
ScrollCaptureSearchResults results =
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 616910a..d6292ca 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -581,7 +581,7 @@
*/
public void reportPerceptible(IBinder windowToken, boolean perceptible) {
try {
- mService.reportPerceptible(windowToken, perceptible);
+ mService.reportPerceptibleAsync(windowToken, perceptible);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
index 20e520e..4365966 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
@@ -30,7 +30,7 @@
*/
oneway interface IInputMethodPrivilegedOperations {
void setImeWindowStatusAsync(int vis, int backDisposition);
- void reportStartInput(in IBinder startInputToken, in IVoidResultCallback resultCallback);
+ void reportStartInputAsync(in IBinder startInputToken);
void createInputContentUriToken(in Uri contentUri, in String packageName,
in IIInputContentUriTokenResultCallback resultCallback);
void reportFullscreenMode(boolean fullscreen, in IVoidResultCallback resultCallback);
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index 1000914..555488d 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -123,21 +123,18 @@
}
/**
- * Calls {@link IInputMethodPrivilegedOperations#reportStartInput(IBinder,
- * IVoidResultCallback)}.
+ * Calls {@link IInputMethodPrivilegedOperations#reportStartInputAsync(IBinder)}.
*
* @param startInputToken {@link IBinder} token to distinguish startInput session
*/
@AnyThread
- public void reportStartInput(IBinder startInputToken) {
+ public void reportStartInputAsync(IBinder startInputToken) {
final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
if (ops == null) {
return;
}
try {
- final Completable.Void value = Completable.createVoid();
- ops.reportStartInput(startInputToken, ResultCallbacks.of(value));
- Completable.getResult(value);
+ ops.reportStartInputAsync(startInputToken);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index fd13c26b..93cd4e9 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -85,7 +85,7 @@
oneway void reportActivityView(in IInputMethodClient parentClient, int childDisplayId,
in float[] matrixValues, in IVoidResultCallback resultCallback);
- oneway void reportPerceptible(in IBinder windowToken, boolean perceptible);
+ oneway void reportPerceptibleAsync(in IBinder windowToken, boolean perceptible);
/** Remove the IME surface. Requires INTERNAL_SYSTEM_WINDOW permission. */
oneway void removeImeSurface(in IVoidResultCallback resultCallback);
/** Remove the IME surface. Requires passing the currently focused window. */
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index ffba628..4194acb 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -30,6 +30,7 @@
#include <android/hardware/display/IDeviceProductInfoConstants.h>
#include <android/os/IInputConstants.h>
#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/android_graphics_GraphicBuffer.h>
#include <android_runtime/android_hardware_HardwareBuffer.h>
#include <android_runtime/android_view_Surface.h>
#include <android_runtime/android_view_SurfaceSession.h>
@@ -253,6 +254,15 @@
}
}
+constexpr ui::Dataspace fromNamedColorSpaceValueToDataspace(const jint colorSpace) {
+ switch (colorSpace) {
+ case JNamedColorSpace::DISPLAY_P3:
+ return ui::Dataspace::DISPLAY_P3;
+ default:
+ return ui::Dataspace::V0_SRGB;
+ }
+}
+
constexpr ui::Dataspace pickDataspaceFromColorMode(const ui::ColorMode colorMode) {
switch (colorMode) {
case ui::ColorMode::DISPLAY_P3:
@@ -553,6 +563,23 @@
transaction->setGeometry(ctrl, source, dst, orientation);
}
+static void nativeSetBuffer(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject,
+ jobject bufferObject) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+ SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
+ sp<GraphicBuffer> buffer(
+ android_graphics_GraphicBuffer_getNativeGraphicsBuffer(env, bufferObject));
+ transaction->setBuffer(ctrl, buffer);
+}
+
+static void nativeSetColorSpace(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject,
+ jint colorSpace) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+ SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
+ ui::Dataspace dataspace = fromNamedColorSpaceValueToDataspace(colorSpace);
+ transaction->setDataspace(ctrl, dataspace);
+}
+
static void nativeSetBlurRegions(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject, jobjectArray regions, jint regionsLength) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
@@ -1877,6 +1904,10 @@
(void*)nativeGetDisplayedContentSample },
{"nativeSetGeometry", "(JJLandroid/graphics/Rect;Landroid/graphics/Rect;J)V",
(void*)nativeSetGeometry },
+ {"nativeSetBuffer", "(JJLandroid/graphics/GraphicBuffer;)V",
+ (void*)nativeSetBuffer },
+ {"nativeSetColorSpace", "(JJI)V",
+ (void*)nativeSetColorSpace },
{"nativeSyncInputWindows", "(J)V",
(void*)nativeSyncInputWindows },
{"nativeGetDisplayBrightnessSupport", "(Landroid/os/IBinder;)Z",
diff --git a/core/proto/android/internal/OWNERS b/core/proto/android/internal/OWNERS
new file mode 100644
index 0000000..24e24c2
--- /dev/null
+++ b/core/proto/android/internal/OWNERS
@@ -0,0 +1,2 @@
+# Binder
+per-file binder_latency.proto = file:/core/java/com/android/internal/os/BINDER_OWNERS
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
index c393d68..8225afc 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
@@ -244,7 +244,8 @@
PendingIntent.getActivity(
context, 0, new Intent("action1"), FLAG_IMMUTABLE)))
.addAction(new RemoteAction(icon1, "title2", "desc2",
- PendingIntent.getActivity(context, 0, new Intent("action2"), 0)))
+ PendingIntent.getActivity(context, 0, new Intent("action2"),
+ FLAG_IMMUTABLE)))
.setEntityType(TextClassifier.TYPE_EMAIL, 0.5f)
.setEntityType(TextClassifier.TYPE_PHONE, 0.4f)
.build();
diff --git a/graphics/java/android/graphics/RecordingCanvas.java b/graphics/java/android/graphics/RecordingCanvas.java
index 6c03ddc..e9e58c6 100644
--- a/graphics/java/android/graphics/RecordingCanvas.java
+++ b/graphics/java/android/graphics/RecordingCanvas.java
@@ -226,10 +226,12 @@
*/
public void drawRipple(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
CanvasProperty<Float> radius, CanvasProperty<Paint> paint,
- CanvasProperty<Float> progress, RuntimeShader shader) {
+ CanvasProperty<Float> progress, CanvasProperty<Float> turbulencePhase,
+ RuntimeShader shader) {
nDrawRipple(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(),
radius.getNativeContainer(), paint.getNativeContainer(),
- progress.getNativeContainer(), shader.getNativeShaderBuilder());
+ progress.getNativeContainer(), turbulencePhase.getNativeContainer(),
+ shader.getNativeShaderBuilder());
}
/**
@@ -290,7 +292,7 @@
long propCy, long propRadius, long propPaint);
@CriticalNative
private static native void nDrawRipple(long renderer, long propCx, long propCy, long propRadius,
- long propPaint, long propProgress, long runtimeEffect);
+ long propPaint, long propProgress, long turbulencePhase, long runtimeEffect);
@CriticalNative
private static native void nDrawRoundRect(long renderer, long propLeft, long propTop,
long propRight, long propBottom, long propRx, long propRy, long propPaint);
diff --git a/graphics/java/android/graphics/drawable/RippleAnimationSession.java b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
index c317831..1cd4cf1 100644
--- a/graphics/java/android/graphics/drawable/RippleAnimationSession.java
+++ b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
@@ -40,6 +40,8 @@
private static final String TAG = "RippleAnimationSession";
private static final int ENTER_ANIM_DURATION = 450;
private static final int EXIT_ANIM_DURATION = 300;
+ private static final long NOISE_ANIMATION_DURATION = 7000;
+ private static final long MAX_NOISE_PHASE = NOISE_ANIMATION_DURATION / 120;
private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
private static final Interpolator FAST_OUT_SLOW_IN =
new PathInterpolator(0.4f, 0f, 0.2f, 1f);
@@ -49,7 +51,7 @@
private Runnable mOnUpdate;
private long mStartTime;
private boolean mForceSoftware;
- private boolean mAnimateSparkle;
+ private Animator mLoopAnimation;
RippleAnimationSession(@NonNull AnimationProperties<Float, Paint> properties,
boolean forceSoftware) {
@@ -88,16 +90,6 @@
return this;
}
- public boolean shouldAnimateSparkle() {
- return mAnimateSparkle && ValueAnimator.getDurationScale() > 0;
- }
-
- public float getSparklePhase() {
- final long now = AnimationUtils.currentAnimationTimeMillis();
- final long elapsed = now - mStartTime;
- return (float) elapsed / 800;
- }
-
private boolean isHwAccelerated(Canvas canvas) {
return canvas.isHardwareAccelerated() && !mForceSoftware;
}
@@ -114,7 +106,7 @@
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
- mAnimateSparkle = false;
+ if (mLoopAnimation != null) mLoopAnimation.cancel();
Consumer<RippleAnimationSession> onEnd = mOnSessionEnd;
if (onEnd != null) onEnd.accept(RippleAnimationSession.this);
}
@@ -148,7 +140,7 @@
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
- mAnimateSparkle = false;
+ if (mLoopAnimation != null) mLoopAnimation.cancel();
Consumer<RippleAnimationSession> onEnd = mOnSessionEnd;
if (onEnd != null) onEnd.accept(RippleAnimationSession.this);
}
@@ -167,24 +159,42 @@
RenderNodeAnimator expand =
new RenderNodeAnimator(props.getProgress(), .5f);
expand.setTarget(canvas);
- startAnimation(expand);
+ RenderNodeAnimator loop = new RenderNodeAnimator(props.getNoisePhase(), MAX_NOISE_PHASE);
+ loop.setTarget(canvas);
+ startAnimation(expand, loop);
}
- private void startAnimation(Animator expand) {
+ private void startAnimation(Animator expand, Animator loop) {
expand.setDuration(ENTER_ANIM_DURATION);
expand.addListener(new AnimatorListener(this));
expand.setInterpolator(FAST_OUT_SLOW_IN);
expand.start();
- mAnimateSparkle = true;
+ loop.setDuration(NOISE_ANIMATION_DURATION);
+ loop.addListener(new AnimatorListener(this) {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ mLoopAnimation = null;
+ }
+ });
+ loop.setInterpolator(LINEAR_INTERPOLATOR);
+ loop.start();
+ if (mLoopAnimation != null) mLoopAnimation.cancel();
+ mLoopAnimation = loop;
}
private void enterSoftware() {
ValueAnimator expand = ValueAnimator.ofFloat(0f, 0.5f);
expand.addUpdateListener(updatedAnimation -> {
notifyUpdate();
- mProperties.getShader().setProgress((Float) expand.getAnimatedValue());
+ mProperties.getShader().setProgress((float) expand.getAnimatedValue());
});
- startAnimation(expand);
+ ValueAnimator loop = ValueAnimator.ofFloat(0f, MAX_NOISE_PHASE);
+ loop.addUpdateListener(updatedAnimation -> {
+ notifyUpdate();
+ mProperties.getShader().setNoisePhase((float) loop.getAnimatedValue());
+ });
+ startAnimation(expand, loop);
}
@NonNull AnimationProperties<Float, Paint> getProperties() {
@@ -198,6 +208,7 @@
CanvasProperty.createFloat(mProperties.getX()),
CanvasProperty.createFloat(mProperties.getY()),
CanvasProperty.createFloat(mProperties.getMaxRadius()),
+ CanvasProperty.createFloat(mProperties.getNoisePhase()),
CanvasProperty.createPaint(mProperties.getPaint()),
CanvasProperty.createFloat(mProperties.getProgress()),
mProperties.getShader());
@@ -236,16 +247,18 @@
static class AnimationProperties<FloatType, PaintType> {
private final FloatType mProgress;
private final FloatType mMaxRadius;
+ private final FloatType mNoisePhase;
private final PaintType mPaint;
private final RippleShader mShader;
private FloatType mX;
private FloatType mY;
- AnimationProperties(FloatType x, FloatType y, FloatType maxRadius,
+ AnimationProperties(FloatType x, FloatType y, FloatType maxRadius, FloatType noisePhase,
PaintType paint, FloatType progress, RippleShader shader) {
mY = y;
mX = x;
mMaxRadius = maxRadius;
+ mNoisePhase = noisePhase;
mPaint = paint;
mShader = shader;
mProgress = progress;
@@ -279,5 +292,9 @@
RippleShader getShader() {
return mShader;
}
+
+ FloatType getNoisePhase() {
+ return mNoisePhase;
+ }
}
}
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 0865332..c972a24 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -858,15 +858,6 @@
}
for (int i = 0; i < mRunningAnimations.size(); i++) {
RippleAnimationSession s = mRunningAnimations.get(i);
- if (s.shouldAnimateSparkle()) {
- final float phase = s.getSparklePhase();
- if (useCanvasProps) {
- s.getCanvasProperties().getShader().setNoisePhase(phase);
- } else {
- s.getProperties().getShader().setNoisePhase(phase);
- }
- invalidateSelf();
- }
if (useCanvasProps) {
RippleAnimationSession.AnimationProperties<CanvasProperty<Float>,
CanvasProperty<Paint>>
@@ -883,7 +874,7 @@
yProp = p.getY();
}
can.drawRipple(xProp, yProp, p.getMaxRadius(), p.getPaint(),
- p.getProgress(), p.getShader());
+ p.getProgress(), p.getNoisePhase(), p.getShader());
} else {
RippleAnimationSession.AnimationProperties<Float, Paint> p =
s.getProperties();
@@ -953,7 +944,7 @@
shader.setRadius(radius);
shader.setProgress(.0f);
properties = new RippleAnimationSession.AnimationProperties<>(
- cx, cy, radius, p, 0f, shader);
+ cx, cy, radius, 0f, p, 0f, shader);
if (mMaskShader == null) {
shader.setShader(null);
} else {
diff --git a/graphics/java/android/graphics/drawable/RippleShader.java b/graphics/java/android/graphics/drawable/RippleShader.java
index 4608d02..c1c6afc 100644
--- a/graphics/java/android/graphics/drawable/RippleShader.java
+++ b/graphics/java/android/graphics/drawable/RippleShader.java
@@ -167,6 +167,9 @@
final float turbulencePhase = (float) ((mProgress + mNoisePhase * 0.333f) * 5f * Math.PI);
setUniform("in_turbulencePhase", turbulencePhase);
+ //
+ // Keep in sync with: frameworks/base/libs/hwui/pipeline/skia/AnimatedDrawables.h
+ //
final float scale = 1.5f;
setUniform("in_tCircle1", new float[]{
(float) (scale * 0.5 + (turbulencePhase * 0.01 * Math.cos(scale * 0.55))),
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index f3baad7..602cd5d 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -43,10 +43,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Superior 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Superior 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Pantalla inferior completa"</string>
- <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Utilizar el modo una mano"</string>
+ <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Usar Modo una mano"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Para salir, desliza el dedo hacia arriba desde la parte inferior de la pantalla o toca cualquier zona que haya encima de la aplicación"</string>
- <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Iniciar modo una mano"</string>
- <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Salir del modo una mano"</string>
+ <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Iniciar Modo una mano"</string>
+ <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Salir del Modo una mano"</string>
<string name="bubbles_settings_button_description" msgid="1301286017420516912">"Ajustes de las burbujas de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Menú adicional"</string>
<string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Volver a añadir a la pila"</string>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index fed3ea9..a17f543 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -62,10 +62,10 @@
<string name="bubbles_user_education_title" msgid="2112319053732691899">"گپ بااستفاده از حبابکها"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"مکالمههای جدید بهصورت نمادهای شناور یا حبابکها نشان داده میشوند. برای باز کردن حبابکها ضربه بزنید. برای جابهجایی، آن را بکشید."</string>
<string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"کنترل حبابکها در هرزمانی"</string>
- <string name="bubbles_user_education_manage" msgid="3460756219946517198">"برای خاموش کردن «حبابکها» از این برنامه، روی «مدیریت» ضربه بزنید"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"برای خاموش کردن حبابکها از این برنامه، روی «مدیریت» ضربه بزنید"</string>
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"متوجهام"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"هیچ حبابک جدیدی وجود ندارد"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"حبابکها اخیر و حبابکها ردشده اینجا ظاهر خواهند شد"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"حبابکهای اخیر و حبابکهای ردشده اینجا ظاهر خواهند شد"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"حباب"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"مدیریت"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"حبابک رد شد."</string>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index a969386..b2c0055 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -67,7 +67,7 @@
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"हाल ही के बबल्स मौजूद नहीं हैं"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"हाल ही के बबल्स और हटाए गए बबल्स यहां दिखेंगे"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"बबल"</string>
- <string name="manage_bubbles_text" msgid="7730624269650594419">"प्रबंधित करें"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"मैनेज करें"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"बबल खारिज किया गया."</string>
<string name="restart_button_description" msgid="5887656107651190519">"इस ऐप्लिकेशन को रीस्टार्ट करने और फ़ुल स्क्रीन पर देखने के लिए टैप करें."</string>
<string name="got_it" msgid="4428750913636945527">"ठीक है"</string>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings_tv.xml b/libs/WindowManager/Shell/res/values-iw/strings_tv.xml
index 8ca54e0..ef98a9c 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings_tv.xml
@@ -19,6 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"תמונה בתוך תמונה"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(תוכנית ללא כותרת)"</string>
- <string name="pip_close" msgid="9135220303720555525">"סגור PIP"</string>
+ <string name="pip_close" msgid="9135220303720555525">"סגירת PIP"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"מסך מלא"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index 530d40a..0c64c76 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -62,7 +62,7 @@
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Калкып чыкма билдирмелер аркылуу маектешүү"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Жаңы жазышуулар калкыма сүрөтчөлөр же калкып чыкма билдирмелер түрүндө көрүнөт. Калкып чыкма билдирмелерди ачуу үчүн таптап коюңуз. Жылдыруу үчүн сүйрөңүз."</string>
<string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Калкып чыкма билдирмелерди каалаган убакта көзөмөлдөңүз"</string>
- <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Бул колдонмодогу калкып чыкма билдирмелерди өчүрүү үчүн, \"Башкарууну\" басыңыз"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Бул колдонмодогу калкып чыкма билдирмелерди өчүрүү үчүн \"Башкарууну\" басыңыз"</string>
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Түшүндүм"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Азырынча эч нерсе жок"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Акыркы жана жабылган калкып чыкма билдирмелер ушул жерде көрүнөт"</string>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index 882ac37..dfa364a 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -30,7 +30,7 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"आकार बदल्नुहोस्"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"एप विभाजित स्क्रिनमा काम नगर्न सक्छ।"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"अनुप्रयोगले विभाजित-स्क्रिनलाई समर्थन गर्दैन।"</string>
- <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"यो अनुप्रयोगले सहायक प्रदर्शनमा काम नगर्नसक्छ।"</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"यो एपले सहायक प्रदर्शनमा काम नगर्नसक्छ।"</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"अनुप्रयोगले सहायक प्रदर्शनहरूमा लञ्च सुविधालाई समर्थन गर्दैन।"</string>
<string name="accessibility_divider" msgid="703810061635792791">"विभाजित-स्क्रिन छुट्याउने"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"बायाँ भाग फुल स्क्रिन"</string>
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index 6698a01..a138fee 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -40,7 +40,7 @@
<integer name="long_press_dock_anim_duration">250</integer>
<!-- Animation duration for translating of one handed when trigger / dismiss. -->
- <integer name="config_one_handed_translate_animation_duration">300</integer>
+ <integer name="config_one_handed_translate_animation_duration">800</integer>
<!-- One handed mode default offset % of display size -->
<fraction name="config_one_handed_offset">40%</fraction>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java
index 125e322..25dd3ca 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java
@@ -22,8 +22,7 @@
import android.content.Context;
import android.graphics.Rect;
import android.view.SurfaceControl;
-import android.view.animation.Interpolator;
-import android.view.animation.OvershootInterpolator;
+import android.view.animation.BaseInterpolator;
import android.window.WindowContainerToken;
import androidx.annotation.VisibleForTesting;
@@ -54,7 +53,7 @@
public @interface TransitionDirection {
}
- private final Interpolator mOvershootInterpolator;
+ private final OneHandedInterpolator mInterpolator;
private final OneHandedSurfaceTransactionHelper mSurfaceTransactionHelper;
private final HashMap<WindowContainerToken, OneHandedTransitionAnimator> mAnimatorMap =
new HashMap<>();
@@ -64,7 +63,7 @@
*/
public OneHandedAnimationController(Context context) {
mSurfaceTransactionHelper = new OneHandedSurfaceTransactionHelper(context);
- mOvershootInterpolator = new OvershootInterpolator();
+ mInterpolator = new OneHandedInterpolator();
}
@SuppressWarnings("unchecked")
@@ -102,7 +101,7 @@
OneHandedTransitionAnimator setupOneHandedTransitionAnimator(
OneHandedTransitionAnimator animator) {
animator.setSurfaceTransactionHelper(mSurfaceTransactionHelper);
- animator.setInterpolator(mOvershootInterpolator);
+ animator.setInterpolator(mInterpolator);
animator.setFloatValues(FRACTION_START, FRACTION_END);
return animator;
}
@@ -112,6 +111,8 @@
*
* @param <T> Type of property to animate, either offset (float)
*/
+ // TODO: Refactoring to use SpringAnimation and DynamicAnimation instead of using ValueAnimator
+ // to implement One-Handed transition animation. (b/185129031)
public abstract static class OneHandedTransitionAnimator<T> extends ValueAnimator implements
ValueAnimator.AnimatorUpdateListener,
ValueAnimator.AnimatorListener {
@@ -297,4 +298,15 @@
};
}
}
+
+ /**
+ * An Interpolator for One-Handed transition animation.
+ */
+ public class OneHandedInterpolator extends BaseInterpolator {
+ @Override
+ public float getInterpolation(float input) {
+ return (float) (Math.pow(2, -10 * input) * Math.sin(((input - 4.0f) / 4.0f)
+ * (2.0f * Math.PI) / 4.0f) + 1);
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index 19098fd..0a86ad8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -343,7 +343,6 @@
mOneHandedAccessibilityUtil.getOneHandedStartDescription());
mDisplayAreaOrganizer.scheduleOffset(0, yOffSet);
mTimeoutHandler.resetTimer();
-
mOneHandedUiEventLogger.writeEvent(
OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_GESTURE_IN);
}
@@ -351,12 +350,7 @@
@VisibleForTesting
void stopOneHanded() {
- if (mDisplayAreaOrganizer.isInOneHanded()) {
- mOneHandedAccessibilityUtil.announcementForScreenReader(
- mOneHandedAccessibilityUtil.getOneHandedStopDescription());
- mDisplayAreaOrganizer.scheduleOffset(0, 0);
- mTimeoutHandler.removeTimer();
- }
+ stopOneHanded(OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_GESTURE_OUT);
}
private void stopOneHanded(int uiEvent) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
index e50bde2..6494f89 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
@@ -23,7 +23,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.LAUNCHER_TITLE
+import com.android.server.wm.flicker.HOME_WINDOW_TITLE
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
@@ -62,7 +62,7 @@
override val ignoredWindows: List<String>
get() = listOf(LAUNCHER_PACKAGE_NAME, LIVE_WALLPAPER_PACKAGE_NAME,
splitScreenApp.defaultWindowName, WindowManagerStateHelper.SPLASH_SCREEN_NAME,
- WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME, *LAUNCHER_TITLE)
+ WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME, *HOME_WINDOW_TITLE)
@FlakyTest(bugId = 169271943)
@Test
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 4c4a152..3056e97 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -820,10 +820,11 @@
uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint,
uirenderer::CanvasPropertyPrimitive* progress,
+ uirenderer::CanvasPropertyPrimitive* turbulencePhase,
const SkRuntimeShaderBuilder& effectBuilder) {
sk_sp<uirenderer::skiapipeline::AnimatedRipple> drawable(
new uirenderer::skiapipeline::AnimatedRipple(x, y, radius, paint, progress,
- effectBuilder));
+ turbulencePhase, effectBuilder));
mCanvas->drawDrawable(drawable.get());
}
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index e0a0be5..995f00c 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -153,6 +153,7 @@
uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint,
uirenderer::CanvasPropertyPrimitive* progress,
+ uirenderer::CanvasPropertyPrimitive* turbulencePhase,
const SkRuntimeShaderBuilder& effectBuilder) override;
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) override;
diff --git a/libs/hwui/canvas/CanvasOps.h b/libs/hwui/canvas/CanvasOps.h
index 855cd0d..173f394 100644
--- a/libs/hwui/canvas/CanvasOps.h
+++ b/libs/hwui/canvas/CanvasOps.h
@@ -152,32 +152,66 @@
sp<uirenderer::CanvasPropertyPrimitive> radius;
sp<uirenderer::CanvasPropertyPaint> paint;
sp<uirenderer::CanvasPropertyPrimitive> progress;
+ sp<uirenderer::CanvasPropertyPrimitive> turbulencePhase;
sk_sp<SkRuntimeEffect> effect;
+ const float PI = 3.1415926535897932384626;
+ const float PI_ROTATE_RIGHT = PI * 0.0078125;
+ const float PI_ROTATE_LEFT = PI * -0.0078125;
+ const float SCALE = 1.5;
+ const float CIRCLE_X_1 = 0.01 * cos(SCALE * 0.55);
+ const float CIRCLE_Y_1 = 0.01 * sin(SCALE * 0.55);
+ const float CIRCLE_X_2 = -0.0066 * cos(SCALE * 0.45);
+ const float CIRCLE_Y_2 = -0.0066 * sin(SCALE * 0.45);
+ const float CIRCLE_X_3 = -0.0066 * cos(SCALE * 0.35);
+ const float CIRCLE_Y_3 = -0.0066 * sin(SCALE * 0.35);
+
void draw(SkCanvas* canvas) const {
SkRuntimeShaderBuilder runtimeEffectBuilder(effect);
- SkRuntimeShaderBuilder::BuilderUniform center = runtimeEffectBuilder.uniform("in_origin");
- if (center.fVar != nullptr) {
- center = SkV2{x->value, y->value};
- }
+ setUniform2f(runtimeEffectBuilder, "in_origin", x->value, y->value);
+ setUniform(runtimeEffectBuilder, "in_radius", radius);
+ setUniform(runtimeEffectBuilder, "in_progress", progress);
+ setUniform(runtimeEffectBuilder, "in_turbulencePhase", turbulencePhase);
- SkRuntimeShaderBuilder::BuilderUniform radiusU =
- runtimeEffectBuilder.uniform("in_radius");
- if (radiusU.fVar != nullptr) {
- radiusU = radius->value;
- }
-
- SkRuntimeShaderBuilder::BuilderUniform progressU =
- runtimeEffectBuilder.uniform("in_progress");
- if (progressU.fVar != nullptr) {
- progressU = progress->value;
- }
+ //
+ // Keep in sync with:
+ // frameworks/base/graphics/java/android/graphics/drawable/RippleShader.java
+ //
+ const float turbulence = turbulencePhase->value;
+ setUniform2f(runtimeEffectBuilder, "in_tCircle1", SCALE * 0.5 + (turbulence * CIRCLE_X_1),
+ SCALE * 0.5 + (turbulence * CIRCLE_Y_1));
+ setUniform2f(runtimeEffectBuilder, "in_tCircle2", SCALE * 0.2 + (turbulence * CIRCLE_X_2),
+ SCALE * 0.2 + (turbulence * CIRCLE_Y_2));
+ setUniform2f(runtimeEffectBuilder, "in_tCircle3", SCALE + (turbulence * CIRCLE_X_3),
+ SCALE + (turbulence * CIRCLE_Y_3));
+ const float rotation1 = turbulence * PI_ROTATE_RIGHT + 1.7 * PI;
+ setUniform2f(runtimeEffectBuilder, "in_tRotation1", cos(rotation1), sin(rotation1));
+ const float rotation2 = turbulence * PI_ROTATE_LEFT + 2 * PI;
+ setUniform2f(runtimeEffectBuilder, "in_tRotation2", cos(rotation2), sin(rotation2));
+ const float rotation3 = turbulence * PI_ROTATE_RIGHT + 2.75 * PI;
+ setUniform2f(runtimeEffectBuilder, "in_tRotation3", cos(rotation3), sin(rotation3));
SkPaint paintMod = paint->value;
paintMod.setShader(runtimeEffectBuilder.makeShader(nullptr, false));
canvas->drawCircle(x->value, y->value, radius->value, paintMod);
}
+
+ void setUniform(SkRuntimeShaderBuilder& effect, std::string name,
+ sp<uirenderer::CanvasPropertyPrimitive> property) const {
+ SkRuntimeShaderBuilder::BuilderUniform uniform = effect.uniform(name.c_str());
+ if (uniform.fVar != nullptr) {
+ uniform = property->value;
+ }
+ }
+
+ void setUniform2f(SkRuntimeShaderBuilder effect, std::string name, float a, float b) const {
+ SkRuntimeShaderBuilder::BuilderUniform uniform = effect.uniform(name.c_str());
+ if (uniform.fVar != nullptr) {
+ uniform = SkV2{a, b};
+ }
+ }
+
ASSERT_DRAWABLE()
};
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index c1feb76..837b055 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -146,6 +146,7 @@
uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint,
uirenderer::CanvasPropertyPrimitive* progress,
+ uirenderer::CanvasPropertyPrimitive* turbulencePhase,
const SkRuntimeShaderBuilder& effectBuilder) = 0;
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) = 0;
diff --git a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
index 855d56e..eb5a88a 100644
--- a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
+++ b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
@@ -141,20 +141,22 @@
canvas->drawCircle(xProp, yProp, radiusProp, paintProp);
}
-static void android_view_DisplayListCanvas_drawRippleProps(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr,
- jlong xPropPtr, jlong yPropPtr,
- jlong radiusPropPtr, jlong paintPropPtr,
- jlong progressPropPtr,
- jlong builderPtr) {
+static void android_view_DisplayListCanvas_drawRippleProps(
+ CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr, jlong xPropPtr, jlong yPropPtr,
+ jlong radiusPropPtr, jlong paintPropPtr, jlong progressPropPtr, jlong turbulencePhasePtr,
+ jlong builderPtr) {
Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
CanvasPropertyPrimitive* radiusProp = reinterpret_cast<CanvasPropertyPrimitive*>(radiusPropPtr);
+ CanvasPropertyPrimitive* turbulencePhaseProp =
+ reinterpret_cast<CanvasPropertyPrimitive*>(turbulencePhasePtr);
CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
CanvasPropertyPrimitive* progressProp =
reinterpret_cast<CanvasPropertyPrimitive*>(progressPropPtr);
SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(builderPtr);
- canvas->drawRipple(xProp, yProp, radiusProp, paintProp, progressProp, *builder);
+ canvas->drawRipple(xProp, yProp, radiusProp, paintProp, progressProp, turbulencePhaseProp,
+ *builder);
}
static void android_view_DisplayListCanvas_drawWebViewFunctor(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr, jint functor) {
@@ -169,19 +171,22 @@
const char* const kClassPathName = "android/graphics/RecordingCanvas";
static JNINativeMethod gMethods[] = {
- // ------------ @CriticalNative --------------
- { "nCreateDisplayListCanvas", "(JII)J", (void*) android_view_DisplayListCanvas_createDisplayListCanvas },
- { "nResetDisplayListCanvas", "(JJII)V", (void*) android_view_DisplayListCanvas_resetDisplayListCanvas },
- { "nGetMaximumTextureWidth", "()I", (void*) android_view_DisplayListCanvas_getMaxTextureSize },
- { "nGetMaximumTextureHeight", "()I", (void*) android_view_DisplayListCanvas_getMaxTextureSize },
- { "nEnableZ", "(JZ)V", (void*) android_view_DisplayListCanvas_enableZ },
- { "nFinishRecording", "(JJ)V", (void*) android_view_DisplayListCanvas_finishRecording },
- { "nDrawRenderNode", "(JJ)V", (void*) android_view_DisplayListCanvas_drawRenderNode },
- { "nDrawTextureLayer", "(JJ)V", (void*) android_view_DisplayListCanvas_drawTextureLayer },
- { "nDrawCircle", "(JJJJJ)V", (void*) android_view_DisplayListCanvas_drawCircleProps },
- { "nDrawRoundRect", "(JJJJJJJJ)V",(void*) android_view_DisplayListCanvas_drawRoundRectProps },
- { "nDrawWebViewFunctor", "(JI)V", (void*) android_view_DisplayListCanvas_drawWebViewFunctor },
- { "nDrawRipple", "(JJJJJJJ)V", (void*) android_view_DisplayListCanvas_drawRippleProps },
+ // ------------ @CriticalNative --------------
+ {"nCreateDisplayListCanvas", "(JII)J",
+ (void*)android_view_DisplayListCanvas_createDisplayListCanvas},
+ {"nResetDisplayListCanvas", "(JJII)V",
+ (void*)android_view_DisplayListCanvas_resetDisplayListCanvas},
+ {"nGetMaximumTextureWidth", "()I", (void*)android_view_DisplayListCanvas_getMaxTextureSize},
+ {"nGetMaximumTextureHeight", "()I",
+ (void*)android_view_DisplayListCanvas_getMaxTextureSize},
+ {"nEnableZ", "(JZ)V", (void*)android_view_DisplayListCanvas_enableZ},
+ {"nFinishRecording", "(JJ)V", (void*)android_view_DisplayListCanvas_finishRecording},
+ {"nDrawRenderNode", "(JJ)V", (void*)android_view_DisplayListCanvas_drawRenderNode},
+ {"nDrawTextureLayer", "(JJ)V", (void*)android_view_DisplayListCanvas_drawTextureLayer},
+ {"nDrawCircle", "(JJJJJ)V", (void*)android_view_DisplayListCanvas_drawCircleProps},
+ {"nDrawRoundRect", "(JJJJJJJJ)V", (void*)android_view_DisplayListCanvas_drawRoundRectProps},
+ {"nDrawWebViewFunctor", "(JI)V", (void*)android_view_DisplayListCanvas_drawWebViewFunctor},
+ {"nDrawRipple", "(JJJJJJJJ)V", (void*)android_view_DisplayListCanvas_drawRippleProps},
};
int register_android_view_DisplayListCanvas(JNIEnv* env) {
diff --git a/libs/hwui/pipeline/skia/AnimatedDrawables.h b/libs/hwui/pipeline/skia/AnimatedDrawables.h
index 7859145..7d65be1 100644
--- a/libs/hwui/pipeline/skia/AnimatedDrawables.h
+++ b/libs/hwui/pipeline/skia/AnimatedDrawables.h
@@ -19,6 +19,7 @@
#include <SkCanvas.h>
#include <SkDrawable.h>
#include <SkRuntimeEffect.h>
+#include <math.h>
#include <utils/RefBase.h>
#include "CanvasProperty.h"
@@ -61,12 +62,14 @@
uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint,
uirenderer::CanvasPropertyPrimitive* progress,
+ uirenderer::CanvasPropertyPrimitive* turbulencePhase,
const SkRuntimeShaderBuilder& effectBuilder)
: mX(x)
, mY(y)
, mRadius(radius)
, mPaint(paint)
, mProgress(progress)
+ , mTurbulencePhase(turbulencePhase)
, mRuntimeEffectBuilder(effectBuilder) {}
protected:
@@ -77,22 +80,28 @@
return SkRect::MakeLTRB(x - radius, y - radius, x + radius, y + radius);
}
virtual void onDraw(SkCanvas* canvas) override {
- SkRuntimeShaderBuilder::BuilderUniform center = mRuntimeEffectBuilder.uniform("in_origin");
- if (center.fVar != nullptr) {
- center = SkV2{mX->value, mY->value};
- }
+ setUniform2f("in_origin", mX->value, mY->value);
+ setUniform("in_radius", mRadius);
+ setUniform("in_progress", mProgress);
+ setUniform("in_turbulencePhase", mTurbulencePhase);
- SkRuntimeShaderBuilder::BuilderUniform radiusU =
- mRuntimeEffectBuilder.uniform("in_radius");
- if (radiusU.fVar != nullptr) {
- radiusU = mRadius->value;
- }
-
- SkRuntimeShaderBuilder::BuilderUniform progressU =
- mRuntimeEffectBuilder.uniform("in_progress");
- if (progressU.fVar != nullptr) {
- progressU = mProgress->value;
- }
+ //
+ // Keep in sync with:
+ // frameworks/base/graphics/java/android/graphics/drawable/RippleShader.java
+ //
+ const float turbulencePhase = mTurbulencePhase->value;
+ setUniform2f("in_tCircle1", SCALE * 0.5 + (turbulencePhase * CIRCLE_X_1),
+ SCALE * 0.5 + (turbulencePhase * CIRCLE_Y_1));
+ setUniform2f("in_tCircle2", SCALE * 0.2 + (turbulencePhase * CIRCLE_X_2),
+ SCALE * 0.2 + (turbulencePhase * CIRCLE_Y_2));
+ setUniform2f("in_tCircle3", SCALE + (turbulencePhase * CIRCLE_X_3),
+ SCALE + (turbulencePhase * CIRCLE_Y_3));
+ const float rotation1 = turbulencePhase * PI_ROTATE_RIGHT + 1.7 * PI;
+ setUniform2f("in_tRotation1", cos(rotation1), sin(rotation1));
+ const float rotation2 = turbulencePhase * PI_ROTATE_LEFT + 2 * PI;
+ setUniform2f("in_tRotation2", cos(rotation2), sin(rotation2));
+ const float rotation3 = turbulencePhase * PI_ROTATE_RIGHT + 2.75 * PI;
+ setUniform2f("in_tRotation3", cos(rotation3), sin(rotation3));
SkPaint paint = mPaint->value;
paint.setShader(mRuntimeEffectBuilder.makeShader(nullptr, false));
@@ -105,7 +114,35 @@
sp<uirenderer::CanvasPropertyPrimitive> mRadius;
sp<uirenderer::CanvasPropertyPaint> mPaint;
sp<uirenderer::CanvasPropertyPrimitive> mProgress;
+ sp<uirenderer::CanvasPropertyPrimitive> mTurbulencePhase;
SkRuntimeShaderBuilder mRuntimeEffectBuilder;
+
+ const float PI = 3.1415926535897932384626;
+ const float PI_ROTATE_RIGHT = PI * 0.0078125;
+ const float PI_ROTATE_LEFT = PI * -0.0078125;
+ const float SCALE = 1.5;
+ const float CIRCLE_X_1 = 0.01 * cos(SCALE * 0.55);
+ const float CIRCLE_Y_1 = 0.01 * sin(SCALE * 0.55);
+ const float CIRCLE_X_2 = -0.0066 * cos(SCALE * 0.45);
+ const float CIRCLE_Y_2 = -0.0066 * sin(SCALE * 0.45);
+ const float CIRCLE_X_3 = -0.0066 * cos(SCALE * 0.35);
+ const float CIRCLE_Y_3 = -0.0066 * sin(SCALE * 0.35);
+
+ virtual void setUniform(std::string name, sp<uirenderer::CanvasPropertyPrimitive> property) {
+ SkRuntimeShaderBuilder::BuilderUniform uniform =
+ mRuntimeEffectBuilder.uniform(name.c_str());
+ if (uniform.fVar != nullptr) {
+ uniform = property->value;
+ }
+ }
+
+ virtual void setUniform2f(std::string name, float a, float b) {
+ SkRuntimeShaderBuilder::BuilderUniform uniform =
+ mRuntimeEffectBuilder.uniform(name.c_str());
+ if (uniform.fVar != nullptr) {
+ uniform = SkV2{a, b};
+ }
+ }
};
class AnimatedCircle : public SkDrawable {
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 82814de..9e73f04 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -60,12 +60,11 @@
// Add the marker annotation to allow HWUI to determine where the current
// clip/transformation should be applied
SkVector vector = rect.getSimpleRadii();
- const int dataSize = 2;
- float data[dataSize];
+ float data[2];
data[0] = vector.x();
data[1] = vector.y();
mRecorder.drawAnnotation(rect.rect(), HOLE_PUNCH_ANNOTATION.c_str(),
- SkData::MakeWithCopy(data, dataSize));
+ SkData::MakeWithCopy(data, 2 * sizeof(float)));
// Clear the current rect within the layer itself
SkPaint paint = SkPaint();
@@ -115,9 +114,10 @@
uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint,
uirenderer::CanvasPropertyPrimitive* progress,
+ uirenderer::CanvasPropertyPrimitive* turbulencePhase,
const SkRuntimeShaderBuilder& effectBuilder) {
drawDrawable(mDisplayList->allocateDrawable<AnimatedRipple>(x, y, radius, paint, progress,
- effectBuilder));
+ turbulencePhase, effectBuilder));
}
void SkiaRecordingCanvas::enableZ(bool enableZ) {
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index 06f2a27..4deb3b9 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -75,6 +75,7 @@
uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint,
uirenderer::CanvasPropertyPrimitive* progress,
+ uirenderer::CanvasPropertyPrimitive* turbulencePhase,
const SkRuntimeShaderBuilder& effectBuilder) override;
virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;
diff --git a/libs/hwui/pipeline/skia/TransformCanvas.cpp b/libs/hwui/pipeline/skia/TransformCanvas.cpp
index 6bfbb0d..a6e4c4c 100644
--- a/libs/hwui/pipeline/skia/TransformCanvas.cpp
+++ b/libs/hwui/pipeline/skia/TransformCanvas.cpp
@@ -22,7 +22,7 @@
void TransformCanvas::onDrawAnnotation(const SkRect& rect, const char* key, SkData* value) {
if (HOLE_PUNCH_ANNOTATION == key) {
- auto* rectParams = static_cast<const float*>(value->data());
+ auto* rectParams = reinterpret_cast<const float*>(value->data());
float radiusX = rectParams[0];
float radiusY = rectParams[1];
SkRRect roundRect = SkRRect::MakeRectXY(rect, radiusX, radiusY);
diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml
index 83cc263..07d04aa 100644
--- a/packages/CompanionDeviceManager/res/values-fa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml
@@ -22,6 +22,6 @@
<string name="profile_name_watch" msgid="576290739483672360">"ساعت"</string>
<string name="confirmation_title" msgid="8455544820286920304">"مجاز کردن <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> برای مدیریت کردن <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_summary" msgid="2059360676631420073">"این برنامه برای مدیریت <xliff:g id="PROFILE_NAME">%1$s</xliff:g> شما لازم است. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
- <string name="consent_yes" msgid="8344487259618762872">"مجاز"</string>
- <string name="consent_no" msgid="2640796915611404382">"مجاز نیست"</string>
+ <string name="consent_yes" msgid="8344487259618762872">"مجاز بودن"</string>
+ <string name="consent_no" msgid="2640796915611404382">"مجاز نبودن"</string>
</resources>
diff --git a/packages/Connectivity/framework/Android.bp b/packages/Connectivity/framework/Android.bp
index c62402d..bb93af9 100644
--- a/packages/Connectivity/framework/Android.bp
+++ b/packages/Connectivity/framework/Android.bp
@@ -100,6 +100,7 @@
"//frameworks/base",
// Tests using hidden APIs
+ "//cts/tests/netlegacy22.api",
"//external/sl4a:__subpackages__",
"//frameworks/base/tests/net:__subpackages__",
"//frameworks/libs/net/common/testutils",
diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt
index 2194575..3ca7475 100644
--- a/packages/Connectivity/framework/api/system-current.txt
+++ b/packages/Connectivity/framework/api/system-current.txt
@@ -277,7 +277,7 @@
method @NonNull public int[] getAdministratorUids();
method @Nullable public static String getCapabilityCarrierName(int);
method @Nullable public String getSsid();
- method @NonNull public java.util.Set<java.lang.Integer> getSubIds();
+ method @NonNull public java.util.Set<java.lang.Integer> getSubscriptionIds();
method @NonNull public int[] getTransportTypes();
method public boolean isPrivateDnsBroken();
method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
@@ -308,7 +308,7 @@
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorUid(int);
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkCapabilities.Builder setSignalStrength(int);
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setSsid(@Nullable String);
- method @NonNull public android.net.NetworkCapabilities.Builder setSubIds(@NonNull java.util.Set<java.lang.Integer>);
+ method @NonNull public android.net.NetworkCapabilities.Builder setSubscriptionIds(@NonNull java.util.Set<java.lang.Integer>);
method @NonNull public android.net.NetworkCapabilities.Builder setTransportInfo(@Nullable android.net.TransportInfo);
}
@@ -338,7 +338,7 @@
public static class NetworkRequest.Builder {
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
- method @NonNull public android.net.NetworkRequest.Builder setSubIds(@NonNull java.util.Set<java.lang.Integer>);
+ method @NonNull public android.net.NetworkRequest.Builder setSubscriptionIds(@NonNull java.util.Set<java.lang.Integer>);
}
public final class NetworkScore implements android.os.Parcelable {
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityFrameworkInitializer.java b/packages/Connectivity/framework/src/android/net/ConnectivityFrameworkInitializer.java
index 92a792b..a2e218d 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityFrameworkInitializer.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityFrameworkInitializer.java
@@ -68,5 +68,11 @@
return cm.startOrGetTestNetworkManager();
}
);
+
+ SystemServiceRegistry.registerContextAwareService(
+ DnsResolverServiceManager.DNS_RESOLVER_SERVICE,
+ DnsResolverServiceManager.class,
+ (context, serviceBinder) -> new DnsResolverServiceManager(serviceBinder)
+ );
}
}
diff --git a/packages/Connectivity/framework/src/android/net/DnsResolverServiceManager.java b/packages/Connectivity/framework/src/android/net/DnsResolverServiceManager.java
new file mode 100644
index 0000000..79009e8
--- /dev/null
+++ b/packages/Connectivity/framework/src/android/net/DnsResolverServiceManager.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net;
+
+import android.annotation.NonNull;
+import android.os.IBinder;
+
+/**
+ * Provides a way to obtain the DnsResolver binder objects.
+ *
+ * @hide
+ */
+public class DnsResolverServiceManager {
+ /** Service name for the DNS resolver. Keep in sync with DnsResolverService.h */
+ public static final String DNS_RESOLVER_SERVICE = "dnsresolver";
+
+ private final IBinder mResolver;
+
+ DnsResolverServiceManager(IBinder resolver) {
+ mResolver = resolver;
+ }
+
+ /**
+ * Get an {@link IBinder} representing the DnsResolver stable AIDL interface
+ *
+ * @return {@link android.net.IDnsResolver} IBinder.
+ */
+ @NonNull
+ public IBinder getService() {
+ return mResolver;
+ }
+}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index c4277c3..775c88f 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -1749,7 +1749,7 @@
combineSSIDs(nc);
combineRequestor(nc);
combineAdministratorUids(nc);
- combineSubIds(nc);
+ combineSubscriptionIds(nc);
}
/**
@@ -1771,7 +1771,7 @@
&& (onlyImmutable || satisfiedByUids(nc))
&& (onlyImmutable || satisfiedBySSID(nc))
&& (onlyImmutable || satisfiedByRequestor(nc))
- && (onlyImmutable || satisfiedBySubIds(nc)));
+ && (onlyImmutable || satisfiedBySubscriptionIds(nc)));
}
/**
@@ -1868,7 +1868,7 @@
&& equalsPrivateDnsBroken(that)
&& equalsRequestor(that)
&& equalsAdministratorUids(that)
- && equalsSubIds(that);
+ && equalsSubscriptionIds(that);
}
@Override
@@ -2346,7 +2346,7 @@
* @hide
*/
@NonNull
- public NetworkCapabilities setSubIds(@NonNull Set<Integer> subIds) {
+ public NetworkCapabilities setSubscriptionIds(@NonNull Set<Integer> subIds) {
mSubIds = new ArraySet(Objects.requireNonNull(subIds));
return this;
}
@@ -2362,14 +2362,14 @@
*/
@NonNull
@SystemApi
- public Set<Integer> getSubIds() {
+ public Set<Integer> getSubscriptionIds() {
return new ArraySet<>(mSubIds);
}
/**
* Tests if the subscription ID set of this network is the same as that of the passed one.
*/
- private boolean equalsSubIds(@NonNull NetworkCapabilities nc) {
+ private boolean equalsSubscriptionIds(@NonNull NetworkCapabilities nc) {
return Objects.equals(mSubIds, nc.mSubIds);
}
@@ -2378,7 +2378,7 @@
* If specified in the request, the passed one need to have at least one subId and at least
* one of them needs to be in the request set.
*/
- private boolean satisfiedBySubIds(@NonNull NetworkCapabilities nc) {
+ private boolean satisfiedBySubscriptionIds(@NonNull NetworkCapabilities nc) {
if (mSubIds.isEmpty()) return true;
if (nc.mSubIds.isEmpty()) return false;
for (final Integer subId : nc.mSubIds) {
@@ -2395,7 +2395,7 @@
* <p>If both subscription IDs are not equal, they belong to different subscription
* (or no subscription). In this case, it would not make sense to add them together.
*/
- private void combineSubIds(@NonNull NetworkCapabilities nc) {
+ private void combineSubscriptionIds(@NonNull NetworkCapabilities nc) {
if (!Objects.equals(mSubIds, nc.mSubIds)) {
throw new IllegalStateException("Can't combine two subscription ID sets");
}
@@ -2737,8 +2737,8 @@
*/
@NonNull
@SystemApi
- public Builder setSubIds(@NonNull final Set<Integer> subIds) {
- mCaps.setSubIds(subIds);
+ public Builder setSubscriptionIds(@NonNull final Set<Integer> subIds) {
+ mCaps.setSubscriptionIds(subIds);
return this;
}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
index 78e1011..90aac0e 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
@@ -508,8 +508,8 @@
*/
@NonNull
@SystemApi
- public Builder setSubIds(@NonNull Set<Integer> subIds) {
- mNetworkCapabilities.setSubIds(subIds);
+ public Builder setSubscriptionIds(@NonNull Set<Integer> subIds) {
+ mNetworkCapabilities.setSubscriptionIds(subIds);
return this;
}
}
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-gu/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-gu/strings.xml
index a24456e..f57061a 100644
--- a/packages/SettingsLib/RestrictedLockUtils/res/values-gu/strings.xml
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-gu/strings.xml
@@ -18,5 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="enabled_by_admin" msgid="6630472777476410137">"વ્યવસ્થાપકે ચાલુ કરેલ"</string>
- <string name="disabled_by_admin" msgid="4023569940620832713">"વ્યવસ્થાપકે બંધ કરેલ"</string>
+ <string name="disabled_by_admin" msgid="4023569940620832713">"વ્યવસ્થાપકે બંધ કરેલું"</string>
</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-it/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-it/strings.xml
index 199a2d6..bddf43c 100644
--- a/packages/SettingsLib/RestrictedLockUtils/res/values-it/strings.xml
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-it/strings.xml
@@ -18,5 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="enabled_by_admin" msgid="6630472777476410137">"Attivata dall\'amministratore"</string>
- <string name="disabled_by_admin" msgid="4023569940620832713">"Disattivata dall\'amministratore"</string>
+ <string name="disabled_by_admin" msgid="4023569940620832713">"Opzione disattivata dall\'amministratore"</string>
</resources>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index a834784..173e959 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -762,7 +762,7 @@
android:showForAllUsers="true"
android:finishOnTaskLaunch="true"
android:launchMode="singleInstance"
- android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
+ android:configChanges="screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden"
android:visibleToInstantApps="true">
</activity>
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 3363f8e..03d844a 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -31,14 +31,16 @@
companion object {
const val ANIMATION_DURATION = 500L
const val ANIMATION_DURATION_FADE_OUT_CONTENT = 183L
- const val ANIMATION_DURATION_FADE_IN_WINDOW = 216L
- const val ANIMATION_DELAY_FADE_IN_WINDOW = 166L
+ const val ANIMATION_DURATION_FADE_IN_WINDOW = 217L
+ const val ANIMATION_DELAY_FADE_IN_WINDOW = 167L
private const val ANIMATION_DURATION_NAV_FADE_IN = 266L
private const val ANIMATION_DURATION_NAV_FADE_OUT = 133L
private const val ANIMATION_DELAY_NAV_FADE_IN =
ANIMATION_DURATION - ANIMATION_DURATION_NAV_FADE_IN
private const val LAUNCH_TIMEOUT = 1000L
+ private val CONTENT_FADE_OUT_INTERPOLATOR = PathInterpolator(0f, 0f, 0.2f, 1f)
+ private val WINDOW_FADE_IN_INTERPOLATOR = PathInterpolator(0f, 0f, 0.6f, 1f)
private val NAV_FADE_IN_INTERPOLATOR = PathInterpolator(0f, 0f, 0f, 1f)
private val NAV_FADE_OUT_INTERPOLATOR = PathInterpolator(0.2f, 0f, 1f, 1f)
@@ -418,12 +420,12 @@
val contentAlphaProgress = getProgress(linearProgress, 0,
ANIMATION_DURATION_FADE_OUT_CONTENT)
state.contentAlpha =
- 1 - Interpolators.ALPHA_OUT.getInterpolation(contentAlphaProgress)
+ 1 - CONTENT_FADE_OUT_INTERPOLATOR.getInterpolation(contentAlphaProgress)
val backgroundAlphaProgress = getProgress(linearProgress,
ANIMATION_DELAY_FADE_IN_WINDOW, ANIMATION_DURATION_FADE_IN_WINDOW)
state.backgroundAlpha =
- 1 - Interpolators.ALPHA_IN.getInterpolation(backgroundAlphaProgress)
+ 1 - WINDOW_FADE_IN_INTERPOLATOR.getInterpolation(backgroundAlphaProgress)
applyStateToWindow(window, state)
navigationBar?.let { applyStateToNavigationBar(it, state, linearProgress) }
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
index 01ec447..3da4521 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
@@ -9,6 +9,7 @@
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
+import android.graphics.drawable.InsetDrawable
import android.graphics.drawable.LayerDrawable
import android.view.GhostView
import android.view.View
@@ -186,6 +187,10 @@
return drawable
}
+ if (drawable is InsetDrawable) {
+ return drawable.drawable?.let { findGradientDrawable(it) }
+ }
+
if (drawable is LayerDrawable) {
for (i in 0 until drawable.numberOfLayers) {
val maybeGradient = drawable.getDrawable(i)
@@ -255,6 +260,11 @@
}
private fun setXfermode(background: Drawable, mode: PorterDuffXfermode?) {
+ if (background is InsetDrawable) {
+ background.drawable?.let { setXfermode(it, mode) }
+ return
+ }
+
if (background !is LayerDrawable) {
background.setXfermode(mode)
return
@@ -323,6 +333,11 @@
return
}
+ if (drawable is InsetDrawable) {
+ drawable.drawable?.let { applyBackgroundRadii(it, radii) }
+ return
+ }
+
if (drawable !is LayerDrawable) {
return
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
index 00bea8d..47a373e 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
@@ -60,6 +60,8 @@
*/
void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade, int flags);
void startActivity(Intent intent, boolean dismissShade);
+ void startActivity(Intent intent, boolean dismissShade,
+ @Nullable ActivityLaunchAnimator.Controller animationController);
void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade);
void startActivity(Intent intent, boolean dismissShade, Callback callback);
void postStartActivityDismissingKeyguard(Intent intent, int delay);
diff --git a/packages/SystemUI/res/drawable/ic_brightness.xml b/packages/SystemUI/res/drawable/ic_brightness.xml
index f443332..842af26 100644
--- a/packages/SystemUI/res/drawable/ic_brightness.xml
+++ b/packages/SystemUI/res/drawable/ic_brightness.xml
@@ -1,29 +1,23 @@
<!--
-Copyright (C) 2020 The Android Open Source Project
+ ~ 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.
+ -->
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
-
- <path
- android:pathData="M18,14.48V18h-3.52L12,20.48L9.52,18H6v-3.52L3.52,12L6,9.52V6h3.52L12,3.52L14.48,6H18v3.52L20.48,12L18,14.48z"
- />
-
- <path
- android:pathData=" M20,8.69 V4h-4.69L12,0.69L8.69,4H4v4.69L0.69,12L4,15.31V20h4.69L12,23.31L15.31,20H20v-4.69L23.31,12L20,8.69z M18,14.48V18h-3.52L12,20.48L9.52,18H6v-3.52L3.52,12L6,9.52V6h3.52L12,3.52L14.48,6H18v3.52L20.48,12L18,14.48z M12,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5s5,-2.24 5,-5S14.76,7 12,7z"
- android:fillColor="#FFFFFF" />
-</vector>
+<level-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Levels in drawables go from 0 to 10000 -->
+ <!-- "One third" of the range per icon -->
+ <item android:maxLevel="3333" android:drawable="@drawable/ic_brightness_low" />
+ <item android:maxLevel="6666" android:drawable="@drawable/ic_brightness_medium" />
+ <item android:maxLevel="10000" android:drawable="@drawable/ic_brightness_full" />
+</level-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_brightness_thumb.xml b/packages/SystemUI/res/drawable/ic_brightness_full.xml
similarity index 86%
rename from packages/SystemUI/res/drawable/ic_brightness_thumb.xml
rename to packages/SystemUI/res/drawable/ic_brightness_full.xml
index d721988..f443332 100644
--- a/packages/SystemUI/res/drawable/ic_brightness_thumb.xml
+++ b/packages/SystemUI/res/drawable/ic_brightness_full.xml
@@ -1,5 +1,5 @@
<!--
-Copyright (C) 2017 The Android Open Source Project
+Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -21,9 +21,9 @@
<path
android:pathData="M18,14.48V18h-3.52L12,20.48L9.52,18H6v-3.52L3.52,12L6,9.52V6h3.52L12,3.52L14.48,6H18v3.52L20.48,12L18,14.48z"
- android:fillColor="?android:attr/colorBackgroundFloating" />
+ />
<path
android:pathData=" M20,8.69 V4h-4.69L12,0.69L8.69,4H4v4.69L0.69,12L4,15.31V20h4.69L12,23.31L15.31,20H20v-4.69L23.31,12L20,8.69z M18,14.48V18h-3.52L12,20.48L9.52,18H6v-3.52L3.52,12L6,9.52V6h3.52L12,3.52L14.48,6H18v3.52L20.48,12L18,14.48z M12,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5s5,-2.24 5,-5S14.76,7 12,7z"
- android:fillColor="?android:attr/colorControlActivated" />
+ android:fillColor="#FFFFFF" />
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_brightness_low.xml b/packages/SystemUI/res/drawable/ic_brightness_low.xml
new file mode 100644
index 0000000..b463556
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_brightness_low.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20,8.69L20,4h-4.69L12,0.69 8.69,4L4,4v4.69L0.69,12 4,15.31L4,20h4.69L12,23.31 15.31,20L20,20v-4.69L23.31,12 20,8.69zM18,14.48L18,18h-3.52L12,20.48 9.52,18L6,18v-3.52L3.52,12 6,9.52L6,6h3.52L12,3.52 14.48,6L18,6v3.52L20.48,12 18,14.48zM12,9c1.65,0 3,1.35 3,3s-1.35,3 -3,3 -3,-1.35 -3,-3 1.35,-3 3,-3m0,-2c-2.76,0 -5,2.24 -5,5s2.24,5 5,5 5,-2.24 5,-5 -2.24,-5 -5,-5z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_brightness_medium.xml b/packages/SystemUI/res/drawable/ic_brightness_medium.xml
new file mode 100644
index 0000000..80acc4d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_brightness_medium.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20,8.69L20,4h-4.69L12,0.69 8.69,4L4,4v4.69L0.69,12 4,15.31L4,20h4.69L12,23.31 15.31,20L20,20v-4.69L23.31,12 20,8.69zM18,14.48L18,18h-3.52L12,20.48 9.52,18L6,18v-3.52L3.52,12 6,9.52L6,6h3.52L12,3.52 14.48,6L18,6v3.52L20.48,12 18,14.48zM12,17c2.76,0 5,-2.24 5,-5s-2.24,-5 -5,-5v10z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/qs_footer_action_chip_background.xml b/packages/SystemUI/res/drawable/qs_footer_action_chip_background.xml
index 6022206..77b9871 100644
--- a/packages/SystemUI/res/drawable/qs_footer_action_chip_background.xml
+++ b/packages/SystemUI/res/drawable/qs_footer_action_chip_background.xml
@@ -23,13 +23,18 @@
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<solid android:color="@android:color/white"/>
+ <corners android:radius="@dimen/screenshot_button_corner_radius"/>
+ </shape>
+ </item>
+ <item>
+ <shape android:shape="rectangle">
+ <solid android:color="?attr/underSurfaceColor"/>
<corners android:radius="@dimen/qs_footer_action_corner_radius"/>
</shape>
</item>
<item>
<shape android:shape="rectangle">
- <stroke android:width="1dp" android:color="@color/qs_footer_action_border"/>
- <solid android:color="@android:color/transparent"/>
+ <stroke android:width="1dp" android:color="@color/qs_footer_action_border"/>
<corners android:radius="@dimen/qs_footer_action_corner_radius"/>
</shape>
</item>
diff --git a/packages/SystemUI/res/drawable/system_animation_ongoing_dot.xml b/packages/SystemUI/res/drawable/system_animation_ongoing_dot.xml
new file mode 100644
index 0000000..4e9d380
--- /dev/null
+++ b/packages/SystemUI/res/drawable/system_animation_ongoing_dot.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<!-- dot drawable for ongoing system privacy events -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+ <solid
+ android:color="@color/privacy_circle"/>
+ <size
+ android:width="6dp"
+ android:height="6dp"
+ />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/people_tile_medium_empty.xml b/packages/SystemUI/res/layout/people_tile_medium_empty.xml
index 7d9cbb9..4236493 100644
--- a/packages/SystemUI/res/layout/people_tile_medium_empty.xml
+++ b/packages/SystemUI/res/layout/people_tile_medium_empty.xml
@@ -14,7 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -22,57 +22,49 @@
<LinearLayout
android:background="@drawable/people_space_tile_view_card"
android:id="@+id/item"
- android:orientation="vertical"
+ android:gravity="center"
+ android:paddingHorizontal="16dp"
+ android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
-
+ <ImageView
+ android:id="@+id/person_icon"
+ android:layout_marginTop="-2dp"
+ android:layout_marginStart="-2dp"
+ android:layout_width="64dp"
+ android:layout_height="64dp" />
+ <ImageView
+ android:id="@+id/availability"
+ android:layout_marginStart="-2dp"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:background="@drawable/circle_green_10dp" />
<LinearLayout
- android:orientation="horizontal"
- android:gravity="center"
- android:layout_gravity="center"
- android:paddingVertical="2dp"
- android:paddingHorizontal="8dp"
+ android:orientation="vertical"
+ android:paddingStart="6dp"
+ android:gravity="top"
android:layout_width="match_parent"
- android:layout_height="match_parent">
- <ImageView
- android:id="@+id/person_icon"
- android:layout_width="64dp"
- android:layout_height="64dp"/>
- <ImageView
- android:id="@+id/availability"
- android:layout_marginStart="-2dp"
- android:layout_width="10dp"
- android:layout_height="10dp"
- android:background="@drawable/circle_green_10dp"/>
- <LinearLayout
- android:orientation="vertical"
- android:paddingStart="6dp"
- android:gravity="top"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <TextView
- android:id="@+id/name"
- android:text="@string/empty_user_name"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="14sp"
- android:maxLines="1"
- android:ellipsize="end"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-
- <TextView
- android:id="@+id/last_interaction"
- android:text="@string/empty_status"
- android:textColor="?android:attr/textColorSecondary"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
- android:textSize="12sp"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:maxLines="3"
- android:ellipsize="end"/>
- </LinearLayout>
+ android:layout_height="wrap_content">
+ <TextView
+ android:id="@+id/name"
+ android:text="@string/empty_user_name"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="14sp"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ <TextView
+ android:id="@+id/last_interaction"
+ android:text="@string/empty_status"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+ android:textSize="12sp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxLines="3"
+ android:ellipsize="end" />
</LinearLayout>
</LinearLayout>
-</LinearLayout>
\ No newline at end of file
+</FrameLayout>
\ No newline at end of file
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 c9e4945..7070660 100644
--- a/packages/SystemUI/res/layout/people_tile_medium_with_content.xml
+++ b/packages/SystemUI/res/layout/people_tile_medium_with_content.xml
@@ -97,7 +97,7 @@
android:gravity="bottom"
android:layout_gravity="center_vertical"
android:orientation="horizontal"
- android:paddingTop="4dp"
+ android:paddingTop="2dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToOutline="true">
diff --git a/packages/SystemUI/res/layout/people_tile_small.xml b/packages/SystemUI/res/layout/people_tile_small.xml
index 34aa8e4..7c28fc1 100644
--- a/packages/SystemUI/res/layout/people_tile_small.xml
+++ b/packages/SystemUI/res/layout/people_tile_small.xml
@@ -21,7 +21,7 @@
<LinearLayout
android:id="@+id/item"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:layout_gravity="center"
android:background="@drawable/people_space_tile_view_card"
android:orientation="vertical"
@@ -42,12 +42,12 @@
android:tint="?android:attr/colorAccent"
android:layout_gravity="center"
android:layout_width="18dp"
- android:layout_height="22dp"
- android:layout_weight="1" />
+ android:layout_height="22dp" />
<TextView
android:id="@+id/messages_count"
android:layout_gravity="center"
+ android:gravity="center"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
@@ -59,7 +59,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
- android:layout_weight="1"
/>
<TextView
@@ -67,7 +66,6 @@
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_weight="1"
android:ellipsize="end"
android:maxLines="1"
android:paddingHorizontal="4dp"
diff --git a/packages/SystemUI/res/layout/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml
index ae3adb8..4fcce24 100644
--- a/packages/SystemUI/res/layout/remote_input.xml
+++ b/packages/SystemUI/res/layout/remote_input.xml
@@ -31,8 +31,7 @@
android:paddingTop="2dp"
android:paddingStart="16dp"
android:paddingEnd="12dp"
- android:layout_marginRight="20dp"
- android:layout_marginLeft="20dp"
+ android:layout_marginLeft="16dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="16dp"
android:layout_gravity="start|center_vertical"
@@ -52,12 +51,10 @@
android:layout_gravity="center_vertical">
<ImageButton
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:paddingLeft="10dp"
- android:layout_marginBottom="12dp"
- android:layout_marginEnd="12dp"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_gravity="center_horizontal|bottom"
+ android:layout_marginBottom="22dp"
android:id="@+id/remote_input_send"
android:src="@drawable/ic_send"
android:contentDescription="@*android:string/ime_action_send"
@@ -69,8 +66,8 @@
android:id="@+id/remote_input_progress"
android:layout_width="24dp"
android:layout_height="24dp"
- android:layout_marginBottom="12dp"
- android:layout_gravity="center_vertical"
+ android:layout_marginBottom="34dp"
+ android:layout_gravity="center_horizontal|bottom"
android:visibility="invisible"
android:indeterminate="true"
style="?android:attr/progressBarStyleSmall" />
diff --git a/packages/SystemUI/res/layout/rounded_corners.xml b/packages/SystemUI/res/layout/rounded_corners.xml
index db892d7..04fe918 100644
--- a/packages/SystemUI/res/layout/rounded_corners.xml
+++ b/packages/SystemUI/res/layout/rounded_corners.xml
@@ -14,6 +14,8 @@
** See the License for the specific language governing permissions and
** limitations under the License.
-->
+
+<!-- TODO: remove this in favor of requiring top and bottom layouts -->
<com.android.systemui.RegionInterceptingFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rounded_corners_default"
@@ -26,6 +28,25 @@
android:layout_gravity="left|top"
android:tint="#ff000000"
android:src="@drawable/rounded"/>
+
+ <FrameLayout
+ android:id="@+id/privacy_dot_left_container"
+ android:layout_height="@dimen/status_bar_height"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="@dimen/status_bar_padding_top"
+ android:layout_marginLeft="8dp"
+ android:layout_gravity="left|top"
+ android:visibility="invisible" >
+ <ImageView
+ android:id="@+id/privacy_dot_left"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center"
+ android:src="@drawable/system_animation_ongoing_dot"
+ android:visibility="visible" />
+ </FrameLayout>
+
+
<ImageView
android:id="@+id/right"
android:layout_width="12dp"
@@ -33,4 +54,22 @@
android:tint="#ff000000"
android:layout_gravity="right|bottom"
android:src="@drawable/rounded"/>
+ <FrameLayout
+ android:id="@+id/privacy_dot_right_container"
+ android:layout_height="@dimen/status_bar_height"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="@dimen/status_bar_padding_top"
+ android:layout_marginRight="8dp"
+ android:layout_gravity="right|top"
+ android:visibility="invisible" >
+ <ImageView
+ android:id="@+id/privacy_dot_right"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center"
+ android:src="@drawable/system_animation_ongoing_dot"
+ android:visibility="visible" />
+
+ </FrameLayout>
+
</com.android.systemui.RegionInterceptingFrameLayout>
diff --git a/packages/SystemUI/res/layout/rounded_corners_bottom.xml b/packages/SystemUI/res/layout/rounded_corners_bottom.xml
index dde1248..720e47b 100644
--- a/packages/SystemUI/res/layout/rounded_corners_bottom.xml
+++ b/packages/SystemUI/res/layout/rounded_corners_bottom.xml
@@ -26,6 +26,24 @@
android:layout_gravity="left|bottom"
android:tint="#ff000000"
android:src="@drawable/rounded_corner_bottom"/>
+
+ <FrameLayout
+ android:id="@+id/privacy_dot_left_container"
+ android:layout_height="@dimen/status_bar_height"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="@dimen/status_bar_padding_top"
+ android:layout_marginLeft="0dp"
+ android:layout_gravity="left|bottom"
+ android:visibility="invisible" >
+ <ImageView
+ android:id="@+id/privacy_dot"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical|right"
+ android:src="@drawable/system_animation_ongoing_dot"
+ android:visibility="visible" />
+ </FrameLayout>
+
<ImageView
android:id="@+id/right"
android:layout_width="12dp"
@@ -33,4 +51,21 @@
android:tint="#ff000000"
android:layout_gravity="right|bottom"
android:src="@drawable/rounded_corner_bottom"/>
+ <FrameLayout
+ android:id="@+id/privacy_dot_right_container"
+ android:layout_height="@dimen/status_bar_height"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="@dimen/status_bar_padding_top"
+ android:layout_marginRight="0dp"
+ android:layout_gravity="right|bottom"
+ android:visibility="invisible" >
+ <ImageView
+ android:id="@+id/privacy_dot"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical|left"
+ android:src="@drawable/system_animation_ongoing_dot"
+ android:visibility="visible" />
+ </FrameLayout>
+
</com.android.systemui.RegionInterceptingFrameLayout>
diff --git a/packages/SystemUI/res/layout/rounded_corners_top.xml b/packages/SystemUI/res/layout/rounded_corners_top.xml
index 813c97d..6abe406 100644
--- a/packages/SystemUI/res/layout/rounded_corners_top.xml
+++ b/packages/SystemUI/res/layout/rounded_corners_top.xml
@@ -26,6 +26,24 @@
android:layout_gravity="left|top"
android:tint="#ff000000"
android:src="@drawable/rounded_corner_top"/>
+
+ <FrameLayout
+ android:id="@+id/privacy_dot_left_container"
+ android:layout_height="@*android:dimen/status_bar_height_portrait"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="@dimen/status_bar_padding_top"
+ android:layout_marginLeft="0dp"
+ android:layout_gravity="left|top"
+ android:visibility="invisible" >
+ <ImageView
+ android:id="@+id/privacy_dot"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical|right"
+ android:src="@drawable/system_animation_ongoing_dot"
+ android:visibility="visible" />
+ </FrameLayout>
+
<ImageView
android:id="@+id/right"
android:layout_width="12dp"
@@ -33,4 +51,24 @@
android:tint="#ff000000"
android:layout_gravity="right|top"
android:src="@drawable/rounded_corner_top"/>
+
+ <FrameLayout
+ android:id="@+id/privacy_dot_right_container"
+ android:layout_height="@*android:dimen/status_bar_height_portrait"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="@dimen/status_bar_padding_top"
+ android:layout_marginRight="0dp"
+ android:layout_gravity="right|top"
+ android:visibility="invisible" >
+ <ImageView
+ android:id="@+id/privacy_dot"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical|left"
+ android:src="@drawable/system_animation_ongoing_dot"
+ android:visibility="visible" />
+
+ </FrameLayout>
+
+
</com.android.systemui.RegionInterceptingFrameLayout>
diff --git a/packages/SystemUI/res/layout/system_event_animation_window.xml b/packages/SystemUI/res/layout/system_event_animation_window.xml
new file mode 100644
index 0000000..c92dec9
--- /dev/null
+++ b/packages/SystemUI/res/layout/system_event_animation_window.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical|end"
+ android:paddingTop="@dimen/status_bar_padding_top"
+ android:paddingEnd="8dp"
+ >
+
+ <ImageView
+ android:id="@+id/dot_view"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:layout_gravity="center_vertical|end"
+ android:src="@drawable/system_animation_ongoing_dot"
+ android:visibility="invisible"
+ />
+
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 62ac75e..5d9c909 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1397,6 +1397,7 @@
<dimen name="max_people_avatar_size_for_large_content">64dp</dimen>
<dimen name="max_people_avatar_size">108dp</dimen>
<dimen name="name_text_size_for_small">14sp</dimen>
+ <dimen name="name_text_size_for_medium">14sp</dimen>
<dimen name="name_text_size_for_large">24sp</dimen>
<dimen name="content_text_size_for_medium">12sp</dimen>
<dimen name="content_text_size_for_large">14sp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
index 983b1bb..62d5a45 100644
--- a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
@@ -91,6 +91,13 @@
}
@Override
+ public void startActivity(Intent intent, boolean dismissShade,
+ @Nullable ActivityLaunchAnimator.Controller animationController) {
+ mActualStarter.ifPresent(
+ starter -> starter.get().startActivity(intent, dismissShade, animationController));
+ }
+
+ @Override
public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade) {
mActualStarter.ifPresent(
starter -> starter.get().startActivity(intent, onlyProvisioned, dismissShade));
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index a686fc0..cbfdce5 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -79,6 +79,8 @@
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.events.PrivacyDotViewController;
+import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.NotificationFilter;
@@ -352,6 +354,8 @@
@Inject Lazy<DeviceConfigProxy> mDeviceConfigProxy;
@Inject Lazy<NavigationBarOverlayController> mNavbarButtonsControllerLazy;
@Inject Lazy<TelephonyListenerManager> mTelephonyListenerManager;
+ @Inject Lazy<SystemStatusAnimationScheduler> mSystemStatusAnimationSchedulerLazy;
+ @Inject Lazy<PrivacyDotViewController> mPrivacyDotViewControllerLazy;
@Inject
public Dependency() {
@@ -561,6 +565,10 @@
mProviders.put(NavigationBarOverlayController.class, mNavbarButtonsControllerLazy::get);
+ mProviders.put(SystemStatusAnimationScheduler.class,
+ mSystemStatusAnimationSchedulerLazy::get);
+ mProviders.put(PrivacyDotViewController.class, mPrivacyDotViewControllerLazy::get);
+
Dependency.setInstance(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 5fa98bc..d07723e 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -88,6 +88,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.qs.SecureSetting;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.events.PrivacyDotViewController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
import com.android.systemui.util.settings.SecureSettings;
@@ -126,6 +127,7 @@
private DisplayManager.DisplayListener mDisplayListener;
private CameraAvailabilityListener mCameraListener;
private final UserTracker mUserTracker;
+ private final PrivacyDotViewController mDotViewController;
//TODO: These are piecemeal being updated to Points for now to support non-square rounded
// corners. for now it is only supposed when reading the intrinsic size from the drawables with
@@ -140,6 +142,11 @@
protected View[] mOverlays;
@Nullable
private DisplayCutoutView[] mCutoutViews;
+ //TODO:
+ View mTopLeftDot;
+ View mTopRightDot;
+ View mBottomLeftDot;
+ View mBottomRightDot;
private float mDensity;
private WindowManager mWindowManager;
private int mRotation;
@@ -147,6 +154,8 @@
private Handler mHandler;
private boolean mPendingRotationChange;
private boolean mIsRoundedCornerMultipleRadius;
+ private int mStatusBarHeightPortrait;
+ private int mStatusBarHeightLandscape;
private CameraAvailabilityListener.CameraTransitionCallback mCameraTransitionCallback =
new CameraAvailabilityListener.CameraTransitionCallback() {
@@ -205,13 +214,15 @@
SecureSettings secureSettings,
BroadcastDispatcher broadcastDispatcher,
TunerService tunerService,
- UserTracker userTracker) {
+ UserTracker userTracker,
+ PrivacyDotViewController dotViewController) {
super(context);
mMainHandler = handler;
mSecureSettings = secureSettings;
mBroadcastDispatcher = broadcastDispatcher;
mTunerService = tunerService;
mUserTracker = userTracker;
+ mDotViewController = dotViewController;
}
@Override
@@ -222,6 +233,7 @@
}
mHandler = startHandlerThread();
mHandler.post(this::startOnScreenDecorationsThread);
+ mDotViewController.setUiExecutor(mHandler::post);
}
@VisibleForTesting
@@ -286,6 +298,7 @@
private void setupDecorations() {
if (hasRoundedCorners() || shouldDrawCutout()) {
+ updateStatusBarHeight();
final DisplayCutout cutout = getCutout();
final Rect[] bounds = cutout == null ? null : cutout.getBoundingRectsAll();
int rotatedPos;
@@ -298,6 +311,10 @@
removeOverlay(i);
}
}
+ // Overlays have been created, send the dots to the controller
+ //TODO: need a better way to do this
+ mDotViewController.initialize(
+ mTopLeftDot, mTopRightDot, mBottomLeftDot, mBottomRightDot);
} else {
removeAllOverlays();
}
@@ -431,14 +448,21 @@
private View overlayForPosition(@BoundsPosition int pos) {
switch (pos) {
case BOUNDS_POSITION_TOP:
- return LayoutInflater.from(mContext)
+ case BOUNDS_POSITION_LEFT:
+ View top = LayoutInflater.from(mContext)
.inflate(R.layout.rounded_corners_top, null);
+ mTopLeftDot = top.findViewById(R.id.privacy_dot_left_container);
+ mTopRightDot = top.findViewById(R.id.privacy_dot_right_container);
+ return top;
case BOUNDS_POSITION_BOTTOM:
- return LayoutInflater.from(mContext)
+ case BOUNDS_POSITION_RIGHT:
+ View bottom = LayoutInflater.from(mContext)
.inflate(R.layout.rounded_corners_bottom, null);
+ mBottomLeftDot = bottom.findViewById(R.id.privacy_dot_left_container);
+ mBottomRightDot = bottom.findViewById(R.id.privacy_dot_right_container);
+ return bottom;
default:
- return LayoutInflater.from(mContext)
- .inflate(R.layout.rounded_corners, null);
+ throw new IllegalArgumentException("Unknown bounds position");
}
}
@@ -575,6 +599,11 @@
View child;
for (int j = 0; j < size; j++) {
child = ((ViewGroup) mOverlays[i]).getChildAt(j);
+ if (child.getId() == R.id.privacy_dot_left_container
+ || child.getId() == R.id.privacy_dot_right_container) {
+ // Exclude privacy dot from color inversion (for now?)
+ continue;
+ }
if (child instanceof ImageView) {
((ImageView) child).setImageTintList(tintList);
} else if (child instanceof DisplayCutoutView) {
@@ -611,10 +640,15 @@
Preconditions.checkState(mHandler.getLooper().getThread() == Thread.currentThread(),
"must call on " + mHandler.getLooper().getThread()
+ ", but was " + Thread.currentThread());
+
+ int newRotation = mContext.getDisplay().getRotation();
+ if (mRotation != newRotation) {
+ mDotViewController.updateRotation(newRotation);
+ }
+
if (mPendingRotationChange) {
return;
}
- int newRotation = mContext.getDisplay().getRotation();
if (newRotation != mRotation) {
mRotation = newRotation;
@@ -630,6 +664,14 @@
}
}
+ private void updateStatusBarHeight() {
+ mStatusBarHeightLandscape = mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height_landscape);
+ mStatusBarHeightPortrait = mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height_portrait);
+ mDotViewController.setStatusBarHeights(mStatusBarHeightPortrait, mStatusBarHeightLandscape);
+ }
+
private void updateRoundedCornerRadii() {
// We should eventually move to just using the intrinsic size of the drawables since
// they should be sized to the exact pixels they want to cover. Therefore I'm purposely not
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsController.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsController.java
index 2661d89..b544599 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsController.java
@@ -60,17 +60,31 @@
/**
* Returns a copy of the list containing all the active AppOps that the controller tracks.
*
- * @return List of active AppOps information
+ * @return List of active AppOps information, without paused elements.
*/
List<AppOpItem> getActiveAppOps();
/**
+ * Returns a copy of the list containing all the active AppOps that the controller tracks.
+ *
+ * @param showPaused {@code true} to also obtain paused items. {@code false} otherwise.
+ * @return List of active AppOps information
+ */
+ List<AppOpItem> getActiveAppOps(boolean showPaused);
+
+ /**
* Returns a copy of the list containing all the active AppOps that the controller tracks, for
* a given user id.
*
* @param userId User id to track
+ * @param showPaused {@code true} to also obtain paused items. {@code false} otherwise.
*
* @return List of active AppOps information for that user id
*/
- List<AppOpItem> getActiveAppOpsForUser(int userId);
+ List<AppOpItem> getActiveAppOpsForUser(int userId, boolean showPaused);
+
+ /**
+ * @return whether this controller is considering the microphone as muted.
+ */
+ boolean isMicMuted();
}
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index 994401d..534f93e 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -241,9 +241,9 @@
AppOpItem item = getAppOpItemLocked(mActiveItems, code, uid, packageName);
if (item == null && active) {
item = new AppOpItem(code, uid, packageName, mClock.elapsedRealtime());
- if (code == AppOpsManager.OP_RECORD_AUDIO) {
+ if (isOpMicrophone(code)) {
item.setDisabled(isAnyRecordingPausedLocked(uid));
- } else if (code == AppOpsManager.OP_CAMERA) {
+ } else if (isOpCamera(code)) {
item.setDisabled(mCameraDisabled);
}
mActiveItems.add(item);
@@ -298,6 +298,11 @@
return PermissionManager.shouldShowPackageForIndicatorCached(mContext, packageName);
}
+ @WorkerThread
+ public List<AppOpItem> getActiveAppOps() {
+ return getActiveAppOps(false);
+ }
+
/**
* Returns a copy of the list containing all the active AppOps that the controller tracks.
*
@@ -306,8 +311,8 @@
* @return List of active AppOps information
*/
@WorkerThread
- public List<AppOpItem> getActiveAppOps() {
- return getActiveAppOpsForUser(UserHandle.USER_ALL);
+ public List<AppOpItem> getActiveAppOps(boolean showPaused) {
+ return getActiveAppOpsForUser(UserHandle.USER_ALL, showPaused);
}
/**
@@ -321,7 +326,7 @@
* @return List of active AppOps information for that user id
*/
@WorkerThread
- public List<AppOpItem> getActiveAppOpsForUser(int userId) {
+ public List<AppOpItem> getActiveAppOpsForUser(int userId, boolean showPaused) {
Assert.isNotMainThread();
List<AppOpItem> list = new ArrayList<>();
synchronized (mActiveItems) {
@@ -330,7 +335,8 @@
AppOpItem item = mActiveItems.get(i);
if ((userId == UserHandle.USER_ALL
|| UserHandle.getUserId(item.getUid()) == userId)
- && isUserVisible(item.getPackageName()) && !item.isDisabled()) {
+ && isUserVisible(item.getPackageName())
+ && (showPaused || !item.isDisabled())) {
list.add(item);
}
}
@@ -441,9 +447,9 @@
AppOpItem item = mActiveItems.get(i);
boolean paused = false;
- if (item.getCode() == AppOpsManager.OP_RECORD_AUDIO) {
+ if (isOpMicrophone(item.getCode())) {
paused = isAnyRecordingPausedLocked(item.getUid());
- } else if (item.getCode() == AppOpsManager.OP_CAMERA) {
+ } else if (isOpCamera(item.getCode())) {
paused = mCameraDisabled;
}
@@ -502,6 +508,19 @@
});
}
+ @Override
+ public boolean isMicMuted() {
+ return mMicMuted;
+ }
+
+ private boolean isOpCamera(int op) {
+ return op == AppOpsManager.OP_CAMERA || op == AppOpsManager.OP_PHONE_CALL_CAMERA;
+ }
+
+ private boolean isOpMicrophone(int op) {
+ return op == AppOpsManager.OP_RECORD_AUDIO || op == AppOpsManager.OP_PHONE_CALL_MICROPHONE;
+ }
+
protected class H extends Handler {
H(Looper looper) {
super(looper);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java b/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java
index de00d50..1a94473 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java
@@ -17,10 +17,20 @@
package com.android.systemui.keyguard;
import android.annotation.IntDef;
+import android.app.IWallpaperManager;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Point;
+import android.os.Bundle;
import android.os.PowerManager;
+import android.os.RemoteException;
import android.os.Trace;
+import android.util.DisplayMetrics;
+
+import androidx.annotation.Nullable;
import com.android.systemui.Dumpable;
+import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import java.io.FileDescriptor;
@@ -31,7 +41,7 @@
import javax.inject.Inject;
/**
- * Tracks the wakefulness lifecycle.
+ * Tracks the wakefulness lifecycle, including why we're waking or sleeping.
*/
@SysUISingleton
public class WakefulnessLifecycle extends Lifecycle<WakefulnessLifecycle.Observer> implements
@@ -51,13 +61,30 @@
public static final int WAKEFULNESS_AWAKE = 2;
public static final int WAKEFULNESS_GOING_TO_SLEEP = 3;
+ private final Context mContext;
+ private final DisplayMetrics mDisplayMetrics;
+ private final IWallpaperManager mWallpaperManagerService;
+
private int mWakefulness = WAKEFULNESS_ASLEEP;
+
private @PowerManager.WakeReason int mLastWakeReason = PowerManager.WAKE_REASON_UNKNOWN;
+
+ @Nullable
+ private Point mLastWakeOriginLocation = null;
+
private @PowerManager.GoToSleepReason int mLastSleepReason =
PowerManager.GO_TO_SLEEP_REASON_MIN;
+ @Nullable
+ private Point mLastSleepOriginLocation = null;
+
@Inject
- public WakefulnessLifecycle() {
+ public WakefulnessLifecycle(
+ Context context,
+ @Nullable IWallpaperManager wallpaperManagerService) {
+ mContext = context;
+ mDisplayMetrics = context.getResources().getDisplayMetrics();
+ mWallpaperManagerService = wallpaperManagerService;
}
public @Wakefulness int getWakefulness() {
@@ -85,6 +112,15 @@
}
setWakefulness(WAKEFULNESS_WAKING);
mLastWakeReason = pmWakeReason;
+ updateLastWakeOriginLocation();
+
+ try {
+ mWallpaperManagerService.notifyWakingUp(
+ mLastWakeOriginLocation.x, mLastWakeOriginLocation.y, new Bundle());
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+
dispatch(Observer::onStartedWakingUp);
}
@@ -102,6 +138,15 @@
}
setWakefulness(WAKEFULNESS_GOING_TO_SLEEP);
mLastSleepReason = pmSleepReason;
+ updateLastSleepOriginLocation();
+
+ try {
+ mWallpaperManagerService.notifyGoingToSleep(
+ mLastSleepOriginLocation.x, mLastSleepOriginLocation.y, new Bundle());
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+
dispatch(Observer::onStartedGoingToSleep);
}
@@ -124,6 +169,60 @@
Trace.traceCounter(Trace.TRACE_TAG_APP, "wakefulness", wakefulness);
}
+ private void updateLastWakeOriginLocation() {
+ mLastWakeOriginLocation = null;
+
+ switch (mLastWakeReason) {
+ case PowerManager.WAKE_REASON_POWER_BUTTON:
+ mLastWakeOriginLocation = getPowerButtonOrigin();
+ break;
+ default:
+ mLastWakeOriginLocation = getDefaultWakeSleepOrigin();
+ break;
+ }
+ }
+
+ private void updateLastSleepOriginLocation() {
+ mLastSleepOriginLocation = null;
+
+ switch (mLastSleepReason) {
+ case PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON:
+ mLastSleepOriginLocation = getPowerButtonOrigin();
+ break;
+ default:
+ mLastSleepOriginLocation = getDefaultWakeSleepOrigin();
+ break;
+ }
+ }
+
+ /**
+ * Returns the point on the screen closest to the physical power button.
+ */
+ private Point getPowerButtonOrigin() {
+ final boolean isPortrait = mContext.getResources().getConfiguration().orientation
+ == Configuration.ORIENTATION_PORTRAIT;
+
+ if (isPortrait) {
+ return new Point(
+ mDisplayMetrics.widthPixels,
+ mContext.getResources().getDimensionPixelSize(
+ R.dimen.physical_power_button_center_screen_location_y));
+ } else {
+ return new Point(
+ mContext.getResources().getDimensionPixelSize(
+ R.dimen.physical_power_button_center_screen_location_y),
+ mDisplayMetrics.heightPixels);
+ }
+ }
+
+ /**
+ * Returns the point on the screen used as the default origin for wake/sleep events. This is the
+ * middle-bottom of the screen.
+ */
+ private Point getDefaultWakeSleepOrigin() {
+ return new Point(mDisplayMetrics.widthPixels / 2, mDisplayMetrics.heightPixels);
+ }
+
public interface Observer {
default void onStartedWakingUp() {}
default void onFinishedWakingUp() {}
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
index a0b5521..38a6186 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
@@ -23,18 +23,14 @@
import static com.android.systemui.people.PeopleTileViewHelper.getSizeInDp;
import android.app.Activity;
-import android.app.INotificationManager;
-import android.app.people.IPeopleManager;
import android.app.people.PeopleSpaceTile;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.LauncherApps;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Outline;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
-import android.os.ServiceManager;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -43,7 +39,6 @@
import com.android.systemui.R;
import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import java.util.ArrayList;
import java.util.List;
@@ -56,19 +51,13 @@
private static final String TAG = "PeopleSpaceActivity";
private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;
- private IPeopleManager mPeopleManager;
private PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
- private INotificationManager mNotificationManager;
- private LauncherApps mLauncherApps;
private Context mContext;
- private NotificationEntryManager mNotificationEntryManager;
private int mAppWidgetId;
@Inject
- public PeopleSpaceActivity(NotificationEntryManager notificationEntryManager,
- PeopleSpaceWidgetManager peopleSpaceWidgetManager) {
+ public PeopleSpaceActivity(PeopleSpaceWidgetManager peopleSpaceWidgetManager) {
super();
- mNotificationEntryManager = notificationEntryManager;
mPeopleSpaceWidgetManager = peopleSpaceWidgetManager;
}
@@ -77,11 +66,6 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = getApplicationContext();
- mNotificationManager = INotificationManager.Stub.asInterface(
- ServiceManager.getService(Context.NOTIFICATION_SERVICE));
- mPeopleManager = IPeopleManager.Stub.asInterface(
- ServiceManager.getService(Context.PEOPLE_SERVICE));
- mLauncherApps = mContext.getSystemService(LauncherApps.class);
mAppWidgetId = getIntent().getIntExtra(EXTRA_APPWIDGET_ID,
INVALID_APPWIDGET_ID);
setResult(RESULT_CANCELED);
@@ -92,10 +76,8 @@
List<PeopleSpaceTile> priorityTiles = new ArrayList<>();
List<PeopleSpaceTile> recentTiles = new ArrayList<>();
try {
- priorityTiles = PeopleSpaceUtils.getPriorityTiles(mContext, mNotificationManager,
- mPeopleManager, mLauncherApps, mNotificationEntryManager);
- recentTiles = PeopleSpaceUtils.getRecentTiles(mContext, mNotificationManager,
- mPeopleManager, mLauncherApps, mNotificationEntryManager);
+ priorityTiles = mPeopleSpaceWidgetManager.getPriorityTiles();
+ recentTiles = mPeopleSpaceWidgetManager.getRecentTiles();
} catch (Exception e) {
Log.e(TAG, "Couldn't retrieve conversations", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
index 0fbe1f7..a160379 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
@@ -19,8 +19,6 @@
import static android.app.Notification.CATEGORY_MISSED_CALL;
import static android.app.Notification.EXTRA_MESSAGES;
-import android.annotation.NonNull;
-import android.app.INotificationManager;
import android.app.Notification;
import android.app.people.ConversationChannel;
import android.app.people.IPeopleManager;
@@ -36,16 +34,13 @@
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.icu.text.MeasureFormat;
-import android.icu.util.Measure;
-import android.icu.util.MeasureUnit;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.ContactsContract;
-import android.service.notification.ConversationChannelWrapper;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.Log;
@@ -65,7 +60,6 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import java.text.SimpleDateFormat;
-import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -73,7 +67,6 @@
import java.util.Date;
import java.util.HashSet;
import java.util.List;
-import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -85,9 +78,6 @@
/** Turns on debugging information about People Space. */
public static final boolean DEBUG = true;
private static final String TAG = "PeopleSpaceUtils";
- private static final int DAYS_IN_A_WEEK = 7;
- private static final int MIN_HOUR = 1;
- private static final int ONE_DAY = 1;
public static final String PACKAGE_NAME = "package_name";
public static final String USER_ID = "user_id";
public static final String SHORTCUT_ID = "shortcut_id";
@@ -127,58 +117,6 @@
}
}
- /** Returns a list of map entries corresponding to user's priority conversations. */
- @NonNull
- public static List<PeopleSpaceTile> getPriorityTiles(
- Context context, INotificationManager notificationManager, IPeopleManager peopleManager,
- LauncherApps launcherApps, NotificationEntryManager notificationEntryManager)
- throws Exception {
- List<ConversationChannelWrapper> conversations =
- notificationManager.getConversations(
- false).getList();
- // Add priority conversations to tiles list.
- Stream<ShortcutInfo> priorityConversations = conversations.stream()
- .filter(c -> c.getNotificationChannel() != null
- && c.getNotificationChannel().isImportantConversation())
- .map(c -> c.getShortcutInfo());
- List<PeopleSpaceTile> priorityTiles = getSortedTiles(peopleManager, launcherApps,
- priorityConversations);
- priorityTiles = augmentTilesFromVisibleNotifications(
- context, priorityTiles, notificationEntryManager);
- return priorityTiles;
- }
-
- /** Returns a list of map entries corresponding to user's recent conversations. */
- @NonNull
- public static List<PeopleSpaceTile> getRecentTiles(
- Context context, INotificationManager notificationManager, IPeopleManager peopleManager,
- LauncherApps launcherApps, NotificationEntryManager notificationEntryManager)
- throws Exception {
- if (DEBUG) Log.d(TAG, "Add recent conversations");
- List<ConversationChannelWrapper> conversations =
- notificationManager.getConversations(
- false).getList();
- Stream<ShortcutInfo> nonPriorityConversations = conversations.stream()
- .filter(c -> c.getNotificationChannel() == null
- || !c.getNotificationChannel().isImportantConversation())
- .map(c -> c.getShortcutInfo());
-
- List<ConversationChannel> recentConversationsList =
- peopleManager.getRecentConversations().getList();
- Stream<ShortcutInfo> recentConversations = recentConversationsList
- .stream()
- .map(c -> c.getShortcutInfo());
-
- Stream<ShortcutInfo> mergedStream = Stream.concat(nonPriorityConversations,
- recentConversations);
- List<PeopleSpaceTile> recentTiles =
- getSortedTiles(peopleManager, launcherApps, mergedStream);
-
- recentTiles = augmentTilesFromVisibleNotifications(
- context, recentTiles, notificationEntryManager);
- return recentTiles;
- }
-
/** Returns stored widgets for the conversation specified. */
public static Set<String> getStoredWidgetIds(SharedPreferences sp, PeopleTileKey key) {
if (!key.isValid()) {
@@ -255,7 +193,8 @@
return augmentedTile.get(0);
}
- static List<PeopleSpaceTile> augmentTilesFromVisibleNotifications(Context context,
+ /** Adds to {@code tiles} any visible notifications. */
+ public static List<PeopleSpaceTile> augmentTilesFromVisibleNotifications(Context context,
List<PeopleSpaceTile> tiles, NotificationEntryManager notificationEntryManager) {
if (notificationEntryManager == null) {
Log.w(TAG, "NotificationEntryManager is null");
@@ -356,11 +295,12 @@
}
/** Returns a list sorted by ascending last interaction time from {@code stream}. */
- private static List<PeopleSpaceTile> getSortedTiles(IPeopleManager peopleManager,
- LauncherApps launcherApps,
+ public static List<PeopleSpaceTile> getSortedTiles(IPeopleManager peopleManager,
+ LauncherApps launcherApps, UserManager userManager,
Stream<ShortcutInfo> stream) {
return stream
.filter(Objects::nonNull)
+ .filter(c -> !userManager.isQuietModeEnabled(c.getUserHandle()))
.map(c -> new PeopleSpaceTile.Builder(c, launcherApps).build())
.filter(c -> shouldKeepConversation(c))
.map(c -> c.toBuilder().setLastInteractionTimestamp(
@@ -426,36 +366,6 @@
return bitmap;
}
- /** Returns a readable status describing the {@code lastInteraction}. */
- public static String getLastInteractionString(Context context, long lastInteraction) {
- if (lastInteraction == 0L) {
- Log.e(TAG, "Could not get valid last interaction");
- return context.getString(R.string.basic_status);
- }
- long now = System.currentTimeMillis();
- Duration durationSinceLastInteraction = Duration.ofMillis(now - lastInteraction);
- MeasureFormat formatter = MeasureFormat.getInstance(Locale.getDefault(),
- MeasureFormat.FormatWidth.WIDE);
- if (durationSinceLastInteraction.toHours() < MIN_HOUR) {
- return context.getString(R.string.timestamp, formatter.formatMeasures(
- new Measure(durationSinceLastInteraction.toMinutes(), MeasureUnit.MINUTE)));
- } else if (durationSinceLastInteraction.toDays() < ONE_DAY) {
- return context.getString(R.string.timestamp, formatter.formatMeasures(
- new Measure(durationSinceLastInteraction.toHours(),
- MeasureUnit.HOUR)));
- } else if (durationSinceLastInteraction.toDays() < DAYS_IN_A_WEEK) {
- return context.getString(R.string.timestamp, formatter.formatMeasures(
- new Measure(durationSinceLastInteraction.toHours(),
- MeasureUnit.DAY)));
- } else {
- return context.getString(durationSinceLastInteraction.toDays() == DAYS_IN_A_WEEK
- ? R.string.timestamp : R.string.over_timestamp,
- formatter.formatMeasures(
- new Measure(durationSinceLastInteraction.toDays() / DAYS_IN_A_WEEK,
- MeasureUnit.WEEK)));
- }
- }
-
/**
* Returns whether the {@code conversation} should be kept for display in the People Space.
*
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
index 51af47d..6b917c5 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
@@ -33,7 +33,6 @@
import static com.android.systemui.people.PeopleSpaceUtils.convertDrawableToBitmap;
import static com.android.systemui.people.PeopleSpaceUtils.getUserId;
-import android.annotation.ColorInt;
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.app.people.ConversationStatus;
@@ -41,27 +40,28 @@
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
-import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
+import android.icu.text.MeasureFormat;
+import android.icu.util.Measure;
+import android.icu.util.MeasureUnit;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.IconDrawableFactory;
import android.util.Log;
-import android.view.ContextThemeWrapper;
import android.view.View;
import android.widget.RemoteViews;
import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.people.widget.LaunchConversationActivity;
import com.android.systemui.people.widget.PeopleSpaceWidgetProvider;
import java.text.NumberFormat;
+import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
@@ -76,6 +76,10 @@
public static final boolean DEBUG = true;
private static final String TAG = "PeopleTileView";
+ private static final int DAYS_IN_A_WEEK = 7;
+ private static final int ONE_DAY = 1;
+ private static final int MAX_WEEKS = 2;
+
public static final int LAYOUT_SMALL = 0;
public static final int LAYOUT_MEDIUM = 1;
public static final int LAYOUT_LARGE = 2;
@@ -83,7 +87,9 @@
private static final int MIN_CONTENT_MAX_LINES = 2;
private static final int FIXED_HEIGHT_DIMENS_FOR_LARGE_CONTENT = 14 + 12 + 4 + 16;
- private static final int FIXED_HEIGHT_DIMENS_FOR_MEDIUM_CONTENT = 8 + 4 + 4 + 8;
+ private static final int MIN_MEDIUM_VERTICAL_PADDING = 4;
+ private static final int MAX_MEDIUM_PADDING = 16;
+ private static final int FIXED_HEIGHT_DIMENS_FOR_MEDIUM_CONTENT_BEFORE_PADDING = 4 + 4;
private static final int FIXED_HEIGHT_DIMENS_FOR_SMALL = 6 + 4 + 8;
private static final int FIXED_WIDTH_DIMENS_FOR_SMALL = 4 + 4;
@@ -96,6 +102,8 @@
public static final String EMPTY_STRING = "";
+ private int mMediumVerticalPadding;
+
private Context mContext;
private PeopleSpaceTile mTile;
private float mDensity;
@@ -205,7 +213,8 @@
private int getContentHeightForLayout(int lineHeight) {
switch (mLayoutSize) {
case LAYOUT_MEDIUM:
- return mHeight - (lineHeight + FIXED_HEIGHT_DIMENS_FOR_MEDIUM_CONTENT);
+ return mHeight - (lineHeight + FIXED_HEIGHT_DIMENS_FOR_MEDIUM_CONTENT_BEFORE_PADDING
+ + mMediumVerticalPadding * 2);
case LAYOUT_LARGE:
return mHeight - (getSizeInDp(
R.dimen.max_people_avatar_size_for_large_content) + lineHeight
@@ -224,7 +233,16 @@
}
// Small layout used below a certain minimum mWidth with any mHeight.
if (mWidth >= getSizeInDp(R.dimen.required_width_for_medium)) {
- if (DEBUG) Log.d(TAG, "Medium view for mWidth: " + mWidth + " mHeight: " + mHeight);
+ int spaceAvailableForPadding =
+ mHeight - (getSizeInDp(R.dimen.avatar_size_for_medium) + 4 + getLineHeight(
+ getSizeInDp(R.dimen.name_text_size_for_medium)));
+ if (DEBUG) {
+ Log.d(TAG, "Medium view for mWidth: " + mWidth + " mHeight: " + mHeight
+ + " with padding space: " + spaceAvailableForPadding);
+ }
+ int maxVerticalPadding = Math.min(Math.floorDiv(spaceAvailableForPadding, 2),
+ MAX_MEDIUM_PADDING);
+ mMediumVerticalPadding = Math.max(MIN_MEDIUM_VERTICAL_PADDING, maxVerticalPadding);
return LAYOUT_MEDIUM;
}
// Small layout can always handle our minimum mWidth and mHeight for our widget.
@@ -347,11 +365,7 @@
setMaxLines(views);
CharSequence content = mTile.getNotificationContent();
views = setPunctuationRemoteViewsFields(views, content);
- // TODO(b/184931139): Update to RemoteViews wrapper to set via attribute once available
- @ColorInt int color = Utils.getColorAttr(mContext,
- android.R.attr.textColorPrimary).getDefaultColor();
- views.setInt(R.id.text_content, "setTextColor", color);
-
+ views.setColorAttr(R.id.text_content, "setTextColor", android.R.attr.textColorPrimary);
views.setTextViewText(R.id.text_content, mTile.getNotificationContent());
views.setViewVisibility(R.id.image, View.GONE);
views.setImageViewResource(R.id.predefined_icon, R.drawable.ic_message);
@@ -398,9 +412,7 @@
views.setViewVisibility(R.id.messages_count, View.GONE);
setMaxLines(views);
// Secondary text color for statuses.
- @ColorInt int secondaryColor = Utils.getColorAttr(mContext,
- android.R.attr.textColorSecondary).getDefaultColor();
- views.setInt(R.id.text_content, "setTextColor", secondaryColor);
+ views.setColorAttr(R.id.text_content, "setTextColor", android.R.attr.textColorSecondary);
views.setTextViewText(R.id.text_content, statusText);
Icon statusIcon = status.getIcon();
@@ -541,6 +553,14 @@
views.setViewVisibility(R.id.text_content, View.VISIBLE);
views.setViewVisibility(R.id.subtext, View.GONE);
}
+
+ if (mLayoutSize == LAYOUT_MEDIUM) {
+ if (DEBUG) Log.d(TAG, "Set vertical padding: " + mMediumVerticalPadding);
+ int horizontalPadding = (int) Math.floor(MAX_MEDIUM_PADDING * mDensity);
+ int verticalPadding = (int) Math.floor(mMediumVerticalPadding * mDensity);
+ views.setViewPadding(R.id.item, horizontalPadding, verticalPadding, horizontalPadding,
+ verticalPadding);
+ }
return views;
}
@@ -551,9 +571,16 @@
views.setViewVisibility(R.id.predefined_icon, View.GONE);
views.setViewVisibility(R.id.messages_count, View.GONE);
}
- String status = PeopleSpaceUtils.getLastInteractionString(mContext,
+ String status = getLastInteractionString(mContext,
mTile.getLastInteractionTimestamp());
- views.setTextViewText(R.id.last_interaction, status);
+ if (status != null) {
+ if (DEBUG) Log.d(TAG, "Show last interaction");
+ views.setViewVisibility(R.id.last_interaction, View.VISIBLE);
+ views.setTextViewText(R.id.last_interaction, status);
+ } else {
+ if (DEBUG) Log.d(TAG, "Hide last interaction");
+ views.setViewVisibility(R.id.last_interaction, View.GONE);
+ }
return views;
}
@@ -599,4 +626,34 @@
hasNewStory);
return convertDrawableToBitmap(personDrawable);
}
+
+ /** Returns a readable status describing the {@code lastInteraction}. */
+ @Nullable
+ public static String getLastInteractionString(Context context, long lastInteraction) {
+ if (lastInteraction == 0L) {
+ Log.e(TAG, "Could not get valid last interaction");
+ return null;
+ }
+ long now = System.currentTimeMillis();
+ Duration durationSinceLastInteraction = Duration.ofMillis(now - lastInteraction);
+ MeasureFormat formatter = MeasureFormat.getInstance(Locale.getDefault(),
+ MeasureFormat.FormatWidth.WIDE);
+ if (durationSinceLastInteraction.toDays() <= ONE_DAY) {
+ return null;
+ } else if (durationSinceLastInteraction.toDays() < DAYS_IN_A_WEEK) {
+ return context.getString(R.string.timestamp, formatter.formatMeasures(
+ new Measure(durationSinceLastInteraction.toHours(),
+ MeasureUnit.DAY)));
+ } else if (durationSinceLastInteraction.toDays() <= DAYS_IN_A_WEEK * 2) {
+ return context.getString(durationSinceLastInteraction.toDays() == DAYS_IN_A_WEEK
+ ? R.string.timestamp : R.string.over_timestamp,
+ formatter.formatMeasures(
+ new Measure(durationSinceLastInteraction.toDays() / DAYS_IN_A_WEEK,
+ MeasureUnit.WEEK)));
+ } else {
+ // Over 2 weeks ago
+ return context.getString(R.string.over_timestamp,
+ formatter.formatMeasures(new Measure(MAX_WEEKS, MeasureUnit.WEEK)));
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java b/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java
index c01a52d..c416b5e 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java
@@ -23,11 +23,13 @@
import android.os.Bundle;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.os.UserManager;
import android.service.notification.NotificationStats;
import android.text.TextUtils;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.UnlaunchableAppActivity;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLoggerImpl;
import com.android.internal.statusbar.IStatusBarService;
@@ -48,15 +50,17 @@
private UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
private NotificationEntryManager mNotificationEntryManager;
private final Optional<BubblesManager> mBubblesManagerOptional;
+ private final UserManager mUserManager;
private boolean mIsForTesting;
private IStatusBarService mIStatusBarService;
@Inject
public LaunchConversationActivity(NotificationEntryManager notificationEntryManager,
- Optional<BubblesManager> bubblesManagerOptional) {
+ Optional<BubblesManager> bubblesManagerOptional, UserManager userManager) {
super();
mNotificationEntryManager = notificationEntryManager;
mBubblesManagerOptional = bubblesManagerOptional;
+ mUserManager = userManager;
}
@Override
@@ -80,12 +84,24 @@
}
mUiEventLogger.log(PeopleSpaceUtils.PeopleSpaceWidgetEvent.PEOPLE_SPACE_WIDGET_CLICKED);
try {
+
+ if (mUserManager.isQuietModeEnabled(userHandle)) {
+ if (DEBUG) Log.d(TAG, "Cannot launch app when quieted");
+ final Intent dialogIntent =
+ UnlaunchableAppActivity.createInQuietModeDialogIntent(
+ userHandle.getIdentifier());
+ this.getApplicationContext().startActivity(dialogIntent);
+ finish();
+ return;
+ }
+
NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(
notificationKey);
if (entry != null && entry.canBubble() && mBubblesManagerOptional.isPresent()) {
if (DEBUG) Log.d(TAG, "Open bubble for conversation");
mBubblesManagerOptional.get().expandStackAndSelectBubble(entry);
// Just opt-out and don't cancel the notification for bubbles.
+ finish();
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
index d63dc4a..6cb7c31 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
@@ -31,7 +31,9 @@
import static com.android.systemui.people.PeopleSpaceUtils.updateAppWidgetOptionsAndView;
import static com.android.systemui.people.PeopleSpaceUtils.updateAppWidgetViews;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.INotificationManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.PendingIntent;
@@ -51,7 +53,9 @@
import android.os.Bundle;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.os.UserManager;
import android.preference.PreferenceManager;
+import android.service.notification.ConversationChannelWrapper;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.Log;
@@ -76,6 +80,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.stream.Stream;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -96,6 +101,8 @@
private NotificationEntryManager mNotificationEntryManager;
private PackageManager mPackageManager;
private PeopleSpaceWidgetProvider mPeopleSpaceWidgetProvider;
+ private INotificationManager mINotificationManager;
+ private UserManager mUserManager;
public UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
@GuardedBy("mLock")
public static Map<PeopleTileKey, PeopleSpaceWidgetProvider.TileConversationListener>
@@ -121,17 +128,21 @@
mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
mPackageManager = mContext.getPackageManager();
mPeopleSpaceWidgetProvider = new PeopleSpaceWidgetProvider();
+ mINotificationManager = INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ mUserManager = context.getSystemService(UserManager.class);
}
/**
* AppWidgetManager setter used for testing.
*/
@VisibleForTesting
- protected void setAppWidgetManager(
+ public void setAppWidgetManager(
AppWidgetManager appWidgetManager, IPeopleManager iPeopleManager,
PeopleManager peopleManager, LauncherApps launcherApps,
NotificationEntryManager notificationEntryManager, PackageManager packageManager,
- boolean isForTesting, PeopleSpaceWidgetProvider peopleSpaceWidgetProvider) {
+ boolean isForTesting, PeopleSpaceWidgetProvider peopleSpaceWidgetProvider,
+ UserManager userManager, INotificationManager notificationManager) {
mAppWidgetManager = appWidgetManager;
mIPeopleManager = iPeopleManager;
mPeopleManager = peopleManager;
@@ -140,6 +151,8 @@
mPackageManager = packageManager;
mIsForTesting = isForTesting;
mPeopleSpaceWidgetProvider = peopleSpaceWidgetProvider;
+ mUserManager = userManager;
+ mINotificationManager = notificationManager;
}
/**
@@ -783,4 +796,52 @@
ComponentName componentName = new ComponentName(mContext, PeopleSpaceWidgetProvider.class);
return mAppWidgetManager.requestPinAppWidget(componentName, extras, successCallback);
}
+
+ /** Returns a list of map entries corresponding to user's priority conversations. */
+ @NonNull
+ public List<PeopleSpaceTile> getPriorityTiles()
+ throws Exception {
+ List<ConversationChannelWrapper> conversations =
+ mINotificationManager.getConversations(true).getList();
+ // Add priority conversations to tiles list.
+ Stream<ShortcutInfo> priorityConversations = conversations.stream()
+ .filter(c -> c.getNotificationChannel() != null
+ && c.getNotificationChannel().isImportantConversation())
+ .map(c -> c.getShortcutInfo());
+ List<PeopleSpaceTile> priorityTiles = PeopleSpaceUtils.getSortedTiles(mIPeopleManager,
+ mLauncherApps, mUserManager,
+ priorityConversations);
+ priorityTiles = PeopleSpaceUtils.augmentTilesFromVisibleNotifications(
+ mContext, priorityTiles, mNotificationEntryManager);
+ return priorityTiles;
+ }
+
+ /** Returns a list of map entries corresponding to user's recent conversations. */
+ @NonNull
+ public List<PeopleSpaceTile> getRecentTiles()
+ throws Exception {
+ if (DEBUG) Log.d(TAG, "Add recent conversations");
+ List<ConversationChannelWrapper> conversations =
+ mINotificationManager.getConversations(false).getList();
+ Stream<ShortcutInfo> nonPriorityConversations = conversations.stream()
+ .filter(c -> c.getNotificationChannel() == null
+ || !c.getNotificationChannel().isImportantConversation())
+ .map(c -> c.getShortcutInfo());
+
+ List<ConversationChannel> recentConversationsList =
+ mIPeopleManager.getRecentConversations().getList();
+ Stream<ShortcutInfo> recentConversations = recentConversationsList
+ .stream()
+ .map(c -> c.getShortcutInfo());
+
+ Stream<ShortcutInfo> mergedStream = Stream.concat(nonPriorityConversations,
+ recentConversations);
+ List<PeopleSpaceTile> recentTiles =
+ PeopleSpaceUtils.getSortedTiles(mIPeopleManager, mLauncherApps, mUserManager,
+ mergedStream);
+
+ recentTiles = PeopleSpaceUtils.augmentTilesFromVisibleNotifications(
+ mContext, recentTiles, mNotificationEntryManager);
+ return recentTiles;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
index f87ea7c..feb27d80 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
@@ -29,6 +29,7 @@
import androidx.annotation.MainThread
import androidx.annotation.VisibleForTesting
import androidx.annotation.WorkerThread
+import com.android.systemui.appops.AppOpsController
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
@@ -48,7 +49,6 @@
return PrivacyDialog(context, list, starter)
}
}
-
/**
* Controller for [PrivacyDialog].
*
@@ -66,6 +66,7 @@
private val uiExecutor: Executor,
private val privacyLogger: PrivacyLogger,
private val keyguardStateController: KeyguardStateController,
+ private val appOpsController: AppOpsController,
@VisibleForTesting private val dialogProvider: DialogProvider
) {
@@ -79,7 +80,8 @@
@Background backgroundExecutor: Executor,
@Main uiExecutor: Executor,
privacyLogger: PrivacyLogger,
- keyguardStateController: KeyguardStateController
+ keyguardStateController: KeyguardStateController,
+ appOpsController: AppOpsController
) : this(
permissionManager,
packageManager,
@@ -90,6 +92,7 @@
uiExecutor,
privacyLogger,
keyguardStateController,
+ appOpsController,
defaultDialogProvider
)
@@ -127,7 +130,9 @@
}
@WorkerThread
- private fun permGroupUsage(): List<PermGroupUsage> = permissionManager.indicatorAppOpUsageData
+ private fun permGroupUsage(): List<PermGroupUsage> {
+ return permissionManager.getIndicatorAppOpUsageData(appOpsController.isMicMuted)
+ }
/**
* Show the [PrivacyDialog]
@@ -261,4 +266,4 @@
starter: (String, Int) -> Unit
): PrivacyDialog
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
index 4c617ed..63ec6e5 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
@@ -54,7 +54,8 @@
data class PrivacyItem(
val privacyType: PrivacyType,
val application: PrivacyApplication,
- val timeStampElapsed: Long = UNKNOWN_TIMESTAMP
+ val timeStampElapsed: Long = UNKNOWN_TIMESTAMP,
+ val paused: Boolean = false
) {
val log = "(${privacyType.logName}, ${application.packageName}(${application.uid}), " +
"$timeStampElapsed)"
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
index f7e2a31..8b27b6e 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
@@ -257,7 +257,7 @@
privacyList = emptyList()
return
}
- val list = appOpsController.getActiveAppOpsForUser(UserHandle.USER_ALL).filter {
+ val list = appOpsController.getActiveAppOps(true).filter {
UserHandle.getUserId(it.uid) in currentUserIds ||
it.code == AppOpsManager.OP_PHONE_CALL_MICROPHONE ||
it.code == AppOpsManager.OP_PHONE_CALL_CAMERA
@@ -279,7 +279,9 @@
// Anything earlier than this timestamp can be removed
val removeBeforeTime = systemClock.elapsedRealtime() - TIME_TO_HOLD_INDICATORS
- val mustKeep = privacyList.filter { it.timeStampElapsed > removeBeforeTime && it !in list }
+ val mustKeep = privacyList.filter {
+ it.timeStampElapsed > removeBeforeTime && !(it isIn list)
+ }
// There are items we must keep because they haven't been around for enough time.
if (mustKeep.isNotEmpty()) {
@@ -291,7 +293,18 @@
logger.logPrivacyItemsUpdateScheduled(delay)
holdingRunnableCanceler = bgExecutor.executeDelayed(updateListAndNotifyChanges, delay)
}
- return list + mustKeep
+ return list.filter { !it.paused } + mustKeep
+ }
+
+ /**
+ * Ignores the paused status to determine if the element is in the list
+ */
+ private infix fun PrivacyItem.isIn(list: List<PrivacyItem>): Boolean {
+ return list.any {
+ it.privacyType == privacyType &&
+ it.application == application &&
+ it.timeStampElapsed == timeStampElapsed
+ }
}
private fun toPrivacyItem(appOpItem: AppOpItem): PrivacyItem? {
@@ -308,7 +321,7 @@
return null
}
val app = PrivacyApplication(appOpItem.packageName, appOpItem.uid)
- return PrivacyItem(type, app, appOpItem.timeStartedElapsed)
+ return PrivacyItem(type, app, appOpItem.timeStartedElapsed, appOpItem.isDisabled)
}
interface Callback {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
index 3467838..74ae3a6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
@@ -32,6 +32,7 @@
import com.android.internal.logging.nano.MetricsProto;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
+import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.globalactions.GlobalActionsDialogLite;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
@@ -65,6 +66,7 @@
private final MetricsLogger mMetricsLogger;
private final FalsingManager mFalsingManager;
private final SettingsButton mSettingsButton;
+ private final View mSettingsButtonContainer;
private final TextView mBuildText;
private final View mEdit;
private final MultiUserSwitch mMultiUserSwitch;
@@ -152,6 +154,7 @@
mFalsingManager = falsingManager;
mSettingsButton = mView.findViewById(R.id.settings_button);
+ mSettingsButtonContainer = mView.findViewById(R.id.settings_button_container);
mBuildText = mView.findViewById(R.id.build);
mEdit = mView.findViewById(android.R.id.edit);
mMultiUserSwitch = mView.findViewById(R.id.multi_user_switch);
@@ -258,10 +261,12 @@
mView.disable(state2, isTunerEnabled());
}
-
private void startSettingsActivity() {
+ ActivityLaunchAnimator.Controller animationController =
+ mSettingsButtonContainer != null ? ActivityLaunchAnimator.Controller.fromView(
+ mSettingsButtonContainer) : null;
mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS),
- true /* dismissShade */);
+ true /* dismissShade */, animationController);
}
private boolean isTunerEnabled() {
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 b728b43..6f19276 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
@@ -184,8 +184,7 @@
@Override
public CharSequence getTileLabel() {
- CharSequence qawLabel = mQuickAccessWalletClient.getServiceLabel();
- return qawLabel == null ? mLabel : qawLabel;
+ return mLabel;
}
private void queryWalletCards() {
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java
index dbd6758..b60fd13 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java
@@ -48,7 +48,7 @@
super(context, attrs);
}
- // Inflated from quick_settings_brightness_dialog or quick_settings_brightness_dialog_thick
+ // Inflated from quick_settings_brightness_dialog
@Override
protected void onFinishInflate() {
super.onFinishInflate();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
new file mode 100644
index 0000000..5ab71bc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
@@ -0,0 +1,352 @@
+/*
+ * 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.events
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ObjectAnimator
+import android.annotation.UiThread
+import android.util.Log
+import android.view.Gravity
+import android.view.View
+import android.widget.FrameLayout
+
+import com.android.systemui.animation.Interpolators
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+
+import java.lang.IllegalStateException
+import java.util.concurrent.Executor
+import javax.inject.Inject
+
+/**
+ * Understands how to keep the persistent privacy dot in the corner of the screen in
+ * ScreenDecorations, which does not rotate with the device.
+ *
+ * The basic principle here is that each dot will sit in a box that is equal to the margins of the
+ * status bar (specifically the status_bar_contents view in PhoneStatusBarView). Each dot container
+ * will have its gravity set towards the corner (i.e., top-right corner gets top|right gravity), and
+ * the contained ImageView will be set to center_vertical and away from the corner horizontally. The
+ * Views will match the status bar top padding and status bar height so that the dot can appear to
+ * reside directly after the status bar system contents (basically to the right of the battery).
+ *
+ * NOTE: any operation that modifies views directly must run on the provided executor, because
+ * these views are owned by ScreenDecorations and it runs in its own thread
+ */
+
+@SysUISingleton
+class PrivacyDotViewController @Inject constructor(
+ @Main val mainExecutor: Executor,
+ val animationScheduler: SystemStatusAnimationScheduler
+) {
+ private var rotation = 0
+ private var leftSize = 0
+ private var rightSize = 0
+
+ private var sbHeightPortrait = 0
+ private var sbHeightLandscape = 0
+
+ private var hasMultipleHeights = false
+ private var needsHeightUpdate = false
+ private var needsRotationUpdate = false
+ private var needsMarginUpdate = false
+
+ private lateinit var tl: View
+ private lateinit var tr: View
+ private lateinit var bl: View
+ private lateinit var br: View
+
+ // Track which corner is active (based on orientation + RTL)
+ private var designatedCorner: View? = null
+
+ // Privacy dots are created in ScreenDecoration's UiThread, which is not the main thread
+ private var uiExecutor: Executor? = null
+
+ private val views: Sequence<View>
+ get() = if (!this::tl.isInitialized) sequenceOf() else sequenceOf(tl, tr, br, bl)
+
+ fun setUiExecutor(e: Executor) {
+ uiExecutor = e
+ }
+
+ @UiThread
+ fun updateRotation(rot: Int) {
+ if (rot == rotation) {
+ return
+ }
+
+ // A rotation has started, hide the views to avoid flicker
+ setCornerVisibilities(View.INVISIBLE)
+
+ if (hasMultipleHeights && (rotation % 2) != (rot % 2)) {
+ // we've changed from vertical to horizontal; update status bar height
+ needsHeightUpdate = true
+ }
+
+ rotation = rot
+ needsRotationUpdate = true
+ }
+
+ @UiThread
+ private fun updateHeights(rot: Int) {
+ val height = when (rot) {
+ 0, 2 -> sbHeightPortrait
+ 1, 3 -> sbHeightLandscape
+ else -> 0
+ }
+
+ views.forEach { it.layoutParams.height = height }
+ }
+
+ // Update the gravity and margins of the privacy views
+ @UiThread
+ private fun updateRotations() {
+ // To keep a view in the corner, its gravity is always the description of its current corner
+ // Therefore, just figure out which view is in which corner. This turns out to be something
+ // like (myCorner - rot) mod 4, where topLeft = 0, topRight = 1, etc. and portrait = 0, and
+ // rotating the device counter-clockwise increments rotation by 1
+
+ views.forEach { corner ->
+ val rotatedCorner = rotatedCorner(cornerForView(corner))
+ (corner.layoutParams as FrameLayout.LayoutParams).apply {
+ gravity = rotatedCorner.toGravity()
+ }
+
+ // Set the dot's view gravity to hug the status bar
+ (corner.findViewById<View>(R.id.privacy_dot)
+ .layoutParams as FrameLayout.LayoutParams)
+ .gravity = rotatedCorner.innerGravity()
+ }
+ }
+
+ @UiThread
+ private fun updateCornerSizes() {
+ views.forEach { corner ->
+ val rotatedCorner = rotatedCorner(cornerForView(corner))
+ val w = widthForCorner(rotatedCorner)
+ Log.d(TAG, "updateCornerSizes: setting (${cornerForView(corner)}) to $w")
+ (corner.layoutParams as FrameLayout.LayoutParams).width = w
+ corner.requestLayout()
+ }
+ }
+
+ // Designated view will be the one at statusbar's view.END
+ @UiThread
+ private fun selectDesignatedCorner(): View? {
+ if (!this::tl.isInitialized) {
+ return null
+ }
+
+ val isRtl = tl.isLayoutRtl
+
+ return when (rotation) {
+ 0 -> if (isRtl) tl else tr
+ 1 -> if (isRtl) tr else br
+ 2 -> if (isRtl) br else bl
+ 3 -> if (isRtl) bl else tl
+ else -> throw IllegalStateException("unknown rotation")
+ }
+ }
+
+ // Track the current designated corner and maybe animate to a new rotation
+ @UiThread
+ private fun updateDesignatedCorner(newCorner: View) {
+ designatedCorner = newCorner
+
+ if (animationScheduler.hasPersistentDot) {
+ designatedCorner!!.visibility = View.VISIBLE
+ designatedCorner!!.alpha = 0f
+ designatedCorner!!.animate()
+ .alpha(1.0f)
+ .setDuration(300)
+ .start()
+ }
+ }
+
+ @UiThread
+ private fun setCornerVisibilities(vis: Int) {
+ views.forEach { corner ->
+ corner.visibility = vis
+ }
+ }
+
+ private fun cornerForView(v: View): Int {
+ return when (v) {
+ tl -> TOP_LEFT
+ tr -> TOP_RIGHT
+ bl -> BOTTOM_LEFT
+ br -> BOTTOM_RIGHT
+ else -> throw IllegalArgumentException("not a corner view")
+ }
+ }
+
+ private fun rotatedCorner(corner: Int): Int {
+ var modded = corner - rotation
+ if (modded < 0) {
+ modded += 4
+ }
+
+ return modded
+ }
+
+ private fun widthForCorner(corner: Int): Int {
+ return when (corner) {
+ TOP_LEFT, BOTTOM_LEFT -> leftSize
+ TOP_RIGHT, BOTTOM_RIGHT -> rightSize
+ else -> throw IllegalArgumentException("Unknown corner")
+ }
+ }
+
+ fun initialize(topLeft: View, topRight: View, bottomLeft: View, bottomRight: View) {
+ if (this::tl.isInitialized && this::tr.isInitialized &&
+ this::bl.isInitialized && this::br.isInitialized) {
+ if (tl == topLeft && tr == topRight && bl == bottomLeft && br == bottomRight) {
+ return
+ }
+ }
+
+ tl = topLeft
+ tr = topRight
+ bl = bottomLeft
+ br = bottomRight
+
+ designatedCorner = selectDesignatedCorner()
+ mainExecutor.execute {
+ animationScheduler.addCallback(systemStatusAnimationCallback)
+ }
+ }
+
+ /**
+ * Set the status bar height in portrait and landscape, in pixels. If they are the same you can
+ * pass the same value twice
+ */
+ fun setStatusBarHeights(portrait: Int, landscape: Int) {
+ sbHeightPortrait = portrait
+ sbHeightLandscape = landscape
+
+ hasMultipleHeights = portrait != landscape
+ }
+
+ /**
+ * The dot view containers will fill the margin in order to position the dots correctly
+ *
+ * @param left the space between the status bar contents and the left side of the screen
+ * @param right space between the status bar contents and the right side of the screen
+ */
+ fun setStatusBarMargins(left: Int, right: Int) {
+ leftSize = left
+ rightSize = right
+
+ needsMarginUpdate = true
+
+ // Margins come after PhoneStatusBarView does a layout pass, and so will always happen
+ // after rotation changes. It is safe to execute the updates from here
+ uiExecutor?.execute {
+ doUpdates(needsRotationUpdate, needsHeightUpdate, needsMarginUpdate)
+ }
+ }
+
+ private fun doUpdates(rot: Boolean, height: Boolean, width: Boolean) {
+ var newDesignatedCorner: View? = null
+
+ if (rot) {
+ needsRotationUpdate = false
+ updateRotations()
+ newDesignatedCorner = selectDesignatedCorner()
+ }
+
+ if (height) {
+ needsHeightUpdate = false
+ updateHeights(rotation)
+ }
+
+ if (width) {
+ needsMarginUpdate = false
+ updateCornerSizes()
+ }
+
+ if (newDesignatedCorner != null && newDesignatedCorner != designatedCorner) {
+ updateDesignatedCorner(newDesignatedCorner)
+ }
+ }
+
+ private val systemStatusAnimationCallback: SystemStatusAnimationCallback =
+ object : SystemStatusAnimationCallback {
+ override fun onSystemStatusAnimationTransitionToPersistentDot(): Animator? {
+ if (designatedCorner == null) {
+ return null
+ }
+
+ val alpha = ObjectAnimator.ofFloat(
+ designatedCorner, "alpha", 0f, 1f)
+ alpha.duration = DURATION
+ alpha.interpolator = Interpolators.ALPHA_OUT
+ alpha.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationStart(animator: Animator) {
+ uiExecutor?.execute { designatedCorner?.visibility = View.VISIBLE }
+ }
+ })
+ return alpha
+ }
+
+ override fun onHidePersistentDot(): Animator? {
+ if (designatedCorner == null) {
+ return null
+ }
+
+ val alpha = ObjectAnimator.ofFloat(
+ designatedCorner, "alpha", 1f, 0f)
+ alpha.duration = DURATION
+ alpha.interpolator = Interpolators.ALPHA_OUT
+ alpha.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animator: Animator) {
+ uiExecutor?.execute { designatedCorner?.visibility = View.INVISIBLE }
+ }
+ })
+ alpha.start()
+ return null
+ }
+ }
+}
+
+const val TOP_LEFT = 0
+const val TOP_RIGHT = 1
+const val BOTTOM_RIGHT = 2
+const val BOTTOM_LEFT = 3
+private const val DURATION = 160L
+private const val TAG = "PrivacyDotViewController"
+
+private fun Int.toGravity(): Int {
+ return when (this) {
+ TOP_LEFT -> Gravity.TOP or Gravity.LEFT
+ TOP_RIGHT -> Gravity.TOP or Gravity.RIGHT
+ BOTTOM_LEFT -> Gravity.BOTTOM or Gravity.LEFT
+ BOTTOM_RIGHT -> Gravity.BOTTOM or Gravity.RIGHT
+ else -> throw IllegalArgumentException("Not a corner")
+ }
+}
+
+private fun Int.innerGravity(): Int {
+ return when (this) {
+ TOP_LEFT -> Gravity.CENTER_VERTICAL or Gravity.RIGHT
+ TOP_RIGHT -> Gravity.CENTER_VERTICAL or Gravity.LEFT
+ BOTTOM_LEFT -> Gravity.CENTER_VERTICAL or Gravity.RIGHT
+ BOTTOM_RIGHT -> Gravity.CENTER_VERTICAL or Gravity.LEFT
+ else -> throw IllegalArgumentException("Not a corner")
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
new file mode 100644
index 0000000..6380dc0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
@@ -0,0 +1,67 @@
+/*
+ * 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.events
+
+import android.content.Context
+import android.graphics.Color
+import android.graphics.drawable.ColorDrawable
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.ImageView
+import com.android.settingslib.graph.ThemedBatteryDrawable
+import com.android.systemui.R
+import com.android.systemui.privacy.OngoingPrivacyChip
+import com.android.systemui.privacy.PrivacyItem
+
+interface StatusEvent {
+ val priority: Int
+ // Whether or not to force the status bar open and show a dot
+ val forceVisible: Boolean
+ val viewCreator: (context: Context) -> View
+}
+
+class BatteryEvent : StatusEvent {
+ override val priority = 50
+ override val forceVisible = false
+
+ override val viewCreator: (context: Context) -> View = { context ->
+ val iv = ImageView(context)
+ iv.setImageDrawable(ThemedBatteryDrawable(context, Color.WHITE))
+ iv.setBackgroundDrawable(ColorDrawable(Color.GREEN))
+ iv
+ }
+
+ override fun toString(): String {
+ return javaClass.simpleName
+ }
+}
+class PrivacyEvent : StatusEvent {
+ override val priority = 100
+ override val forceVisible = true
+ var privacyItems: List<PrivacyItem> = listOf()
+
+ override val viewCreator: (context: Context) -> View = { context ->
+ val v = LayoutInflater.from(context)
+ .inflate(R.layout.ongoing_privacy_chip, null) as OngoingPrivacyChip
+ v.privacyList = privacyItems
+ v
+ }
+
+ override fun toString(): String {
+ return javaClass.simpleName
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
new file mode 100644
index 0000000..6209630
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
@@ -0,0 +1,137 @@
+/*
+ * 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.events
+
+import android.animation.ValueAnimator
+import android.content.Context
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup.LayoutParams.MATCH_PARENT
+import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
+import android.widget.FrameLayout
+
+import com.android.systemui.R
+import com.android.systemui.statusbar.SuperStatusBarViewFactory
+import com.android.systemui.statusbar.phone.StatusBarWindowController
+import com.android.systemui.statusbar.phone.StatusBarWindowView
+
+import javax.inject.Inject
+
+/**
+ * //TODO: this _probably_ doesn't control a window anymore
+ * Controls the window for system event animations.
+ */
+class SystemEventChipAnimationController @Inject constructor(
+ private val context: Context,
+ private val statusBarViewFactory: SuperStatusBarViewFactory,
+ private val statusBarWindowController: StatusBarWindowController
+) : SystemStatusChipAnimationCallback {
+ var showPersistentDot = false
+ set(value) {
+ field = value
+ statusBarWindowController.setForceStatusBarVisible(value)
+ maybeUpdateShowDot()
+ }
+
+ private lateinit var animationWindowView: FrameLayout
+ private lateinit var animationDotView: View
+ private lateinit var statusBarWindowView: StatusBarWindowView
+ private var currentAnimatedView: View? = null
+
+ // TODO: move to dagger
+ private var initialized = false
+
+ override fun onChipAnimationStart(
+ viewCreator: (context: Context) -> View,
+ @SystemAnimationState state: Int
+ ) {
+ if (!initialized) init()
+
+ if (state == ANIMATING_IN) {
+ currentAnimatedView = viewCreator(context)
+ animationWindowView.addView(currentAnimatedView, layoutParamsDefault)
+
+ // We are animating IN; chip comes in from View.END
+ currentAnimatedView?.apply {
+ translationX = width.toFloat()
+ alpha = 0f
+ visibility = View.VISIBLE
+ }
+ } else {
+ // We are animating away
+ currentAnimatedView?.apply {
+ translationX = 0f
+ alpha = 1f
+ }
+ }
+ }
+
+ override fun onChipAnimationEnd(@SystemAnimationState state: Int) {
+ if (state == ANIMATING_IN) {
+ // Finished animating in
+ currentAnimatedView?.apply {
+ translationX = 0f
+ alpha = 1f
+ }
+ } else {
+ // Finished animating away
+ currentAnimatedView?.apply {
+ visibility = View.INVISIBLE
+ }
+ animationWindowView.removeView(currentAnimatedView)
+ }
+ }
+
+ override fun onChipAnimationUpdate(
+ animator: ValueAnimator,
+ @SystemAnimationState state: Int
+ ) {
+ // Alpha is parameterized 0,1, and translation from (width, 0)
+ currentAnimatedView?.apply {
+ val amt = animator.animatedValue as Float
+
+ alpha = amt
+
+ val w = width
+ val translation = (1 - amt) * w
+ translationX = translation
+ }
+ }
+
+ private fun maybeUpdateShowDot() {
+ if (!initialized) return
+ if (!showPersistentDot && currentAnimatedView == null) {
+ animationDotView.visibility = View.INVISIBLE
+ }
+ }
+
+ private fun init() {
+ initialized = true
+ statusBarWindowView = statusBarViewFactory.statusBarWindowView
+ animationWindowView = LayoutInflater.from(context)
+ .inflate(R.layout.system_event_animation_window, null) as FrameLayout
+ animationDotView = animationWindowView.findViewById(R.id.dot_view)
+ val lp = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
+ lp.gravity = Gravity.END or Gravity.CENTER_VERTICAL
+ statusBarWindowView.addView(animationWindowView, lp)
+ }
+
+ private val layoutParamsDefault = FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).also {
+ it.gravity = Gravity.END or Gravity.CENTER_VERTICAL
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt
new file mode 100644
index 0000000..b481823
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt
@@ -0,0 +1,112 @@
+/*
+ * 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.events
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.privacy.PrivacyItem
+import com.android.systemui.privacy.PrivacyItemController
+import com.android.systemui.statusbar.policy.BatteryController
+import javax.inject.Inject
+
+/**
+ * Listens for system events (battery, privacy, connectivity) and allows listeners
+ * to show status bar animations when they happen
+ */
+@SysUISingleton
+class SystemEventCoordinator @Inject constructor(
+ private val batteryController: BatteryController,
+ private val privacyController: PrivacyItemController
+) {
+ private lateinit var scheduler: SystemStatusAnimationScheduler
+
+ fun startObserving() {
+ /* currently unused
+ batteryController.addCallback(batteryStateListener)
+ */
+ privacyController.addCallback(privacyStateListener)
+ }
+
+ fun stopObserving() {
+ /* currently unused
+ batteryController.removeCallback(batteryStateListener)
+ */
+ privacyController.removeCallback(privacyStateListener)
+ }
+
+ fun attachScheduler(s: SystemStatusAnimationScheduler) {
+ this.scheduler = s
+ }
+
+ fun notifyPluggedIn() {
+ scheduler.onStatusEvent(BatteryEvent())
+ }
+
+ fun notifyPrivacyItemsEmpty() {
+ scheduler.setShouldShowPersistentPrivacyIndicator(false)
+ }
+
+ fun notifyPrivacyItemsChanged() {
+ val event = PrivacyEvent()
+ event.privacyItems = privacyStateListener.currentPrivacyItems
+ scheduler.onStatusEvent(event)
+ }
+
+ private val batteryStateListener = object : BatteryController.BatteryStateChangeCallback {
+ var plugged = false
+ var stateKnown = false
+ override fun onBatteryLevelChanged(level: Int, pluggedIn: Boolean, charging: Boolean) {
+ if (!stateKnown) {
+ stateKnown = true
+ plugged = pluggedIn
+ notifyListeners()
+ return
+ }
+
+ if (plugged != pluggedIn) {
+ plugged = pluggedIn
+ notifyListeners()
+ }
+ }
+
+ private fun notifyListeners() {
+ // We only care about the plugged in status
+ if (plugged) notifyPluggedIn()
+ }
+ }
+
+ private val privacyStateListener = object : PrivacyItemController.Callback {
+ var currentPrivacyItems = listOf<PrivacyItem>()
+
+ override fun onPrivacyItemsChanged(privacyItems: List<PrivacyItem>) {
+ if (privacyItems.isNotEmpty() && currentPrivacyItems.containsAll(privacyItems)) {
+ return
+ }
+ currentPrivacyItems = privacyItems
+ notifyListeners()
+ }
+
+ private fun notifyListeners() {
+ if (currentPrivacyItems.isEmpty()) {
+ notifyPrivacyItemsEmpty()
+ } else {
+ notifyPrivacyItemsChanged()
+ }
+ }
+ }
+}
+
+private const val TAG = "SystemEventCoordinator"
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
new file mode 100644
index 0000000..b85d031
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
@@ -0,0 +1,333 @@
+/*
+ * 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.events
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.AnimatorSet
+import android.animation.ValueAnimator
+import android.annotation.IntDef
+import android.content.Context
+import android.os.Process
+import android.util.Log
+import android.view.View
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+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 javax.inject.Inject
+
+/**
+ * Dead-simple scheduler for system status events. Obeys the following principles (all values TBD):
+ * - Avoiding log spam by only allowing 12 events per minute (1event/5s)
+ * - Waits 100ms to schedule any event for debouncing/prioritization
+ * - Simple prioritization: Privacy > Battery > connectivity (encoded in StatusEvent)
+ * - Only schedules a single event, and throws away lowest priority events
+ *
+ * There are 4 basic stages of animation at play here:
+ * 1. System chrome animation OUT
+ * 2. Chip animation IN
+ * 3. Chip animation OUT; potentially into a dot
+ * 4. System chrome animation IN
+ *
+ * Thus we can keep all animations synchronized with two separate ValueAnimators, one for system
+ * chrome and the other for the chip. These can animate from 0,1 and listeners can parameterize
+ * their respective views based on the progress of the animator. Interpolation differences TBD
+ */
+@SysUISingleton
+class SystemStatusAnimationScheduler @Inject constructor(
+ private val coordinator: SystemEventCoordinator,
+ private val chipAnimationController: SystemEventChipAnimationController,
+ private val statusBarWindowController: StatusBarWindowController,
+ private val systemClock: SystemClock,
+ @Main private val executor: DelayableExecutor
+) : CallbackController<SystemStatusAnimationCallback> {
+
+ /** 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
+
+ /** True if the persistent privacy dot should be active */
+ var hasPersistentDot = false
+ private set
+
+ private var scheduledEvent: StatusEvent? = null
+ private var cancelExecutionRunnable: Runnable? = null
+ private val listeners = mutableSetOf<SystemStatusAnimationCallback>()
+
+ init {
+ coordinator.attachScheduler(this)
+ }
+
+ fun onStatusEvent(event: StatusEvent) {
+ // Ignore any updates until the system is up and running
+ if (isTooEarly()) {
+ return
+ }
+
+ // Don't deal with threading for now (no need let's be honest)
+ Assert.isMainThread()
+ if (event.priority > scheduledEvent?.priority ?: -1) {
+ if (DEBUG) {
+ Log.d(TAG, "scheduling event $event")
+ }
+ scheduleEvent(event)
+ } else {
+ if (DEBUG) {
+ Log.d(TAG, "ignoring event $event")
+ }
+ }
+ }
+
+ private fun clearDotIfVisible() {
+ notifyHidePersistentDot()
+ }
+
+ fun setShouldShowPersistentPrivacyIndicator(should: Boolean) {
+ if (hasPersistentDot == should) {
+ return
+ }
+
+ hasPersistentDot = should
+
+ if (!hasPersistentDot) {
+ clearDotIfVisible()
+ }
+ }
+
+ private fun isTooEarly(): Boolean {
+ Log.d(TAG, "time=> ${systemClock.uptimeMillis() - Process.getStartUptimeMillis()}")
+ return systemClock.uptimeMillis() - Process.getStartUptimeMillis() < MIN_UPTIME
+ }
+
+ /**
+ * Clear the scheduled event (if any) and schedule a new one
+ */
+ private fun scheduleEvent(event: StatusEvent) {
+ scheduledEvent = event
+ if (scheduledEvent!!.forceVisible) {
+ hasPersistentDot = true
+ }
+
+ // Schedule the animation to start after a debounce period
+ cancelExecutionRunnable = executor.executeDelayed({
+ cancelExecutionRunnable = null
+ animationState = ANIMATING_IN
+ statusBarWindowController.setForceStatusBarVisible(true)
+
+ val entranceAnimator = ValueAnimator.ofFloat(1f, 0f)
+ entranceAnimator.duration = ENTRANCE_ANIM_LENGTH
+ entranceAnimator.addListener(systemAnimatorAdapter)
+ entranceAnimator.addUpdateListener(systemUpdateListener)
+
+ val chipAnimator = ValueAnimator.ofFloat(0f, 1f)
+ chipAnimator.duration = CHIP_ANIM_LENGTH
+ chipAnimator.addListener(
+ ChipAnimatorAdapter(RUNNING_CHIP_ANIM, scheduledEvent!!.viewCreator))
+ chipAnimator.addUpdateListener(chipUpdateListener)
+
+ val aSet2 = AnimatorSet()
+ aSet2.playSequentially(entranceAnimator, chipAnimator)
+ aSet2.start()
+
+ executor.executeDelayed({
+ animationState = ANIMATING_OUT
+
+ val systemAnimator = ValueAnimator.ofFloat(0f, 1f)
+ systemAnimator.duration = ENTRANCE_ANIM_LENGTH
+ systemAnimator.addListener(systemAnimatorAdapter)
+ systemAnimator.addUpdateListener(systemUpdateListener)
+
+ val chipAnimator = ValueAnimator.ofFloat(1f, 0f)
+ chipAnimator.duration = CHIP_ANIM_LENGTH
+ chipAnimator.addListener(ChipAnimatorAdapter(IDLE, scheduledEvent!!.viewCreator))
+ chipAnimator.addUpdateListener(chipUpdateListener)
+
+ val aSet2 = AnimatorSet()
+
+ aSet2.play(chipAnimator).before(systemAnimator)
+ if (hasPersistentDot) {
+ val dotAnim = notifyTransitionToPersistentDot()
+ if (dotAnim != null) aSet2.playTogether(systemAnimator, dotAnim)
+ }
+
+ aSet2.start()
+
+ statusBarWindowController.setForceStatusBarVisible(false)
+ scheduledEvent = null
+ }, DISPLAY_LENGTH)
+ }, DELAY)
+ }
+
+ private fun notifyTransitionToPersistentDot(): Animator? {
+ val anims: List<Animator> = listeners.mapNotNull {
+ it.onSystemStatusAnimationTransitionToPersistentDot()
+ }
+ if (anims.isNotEmpty()) {
+ val aSet = AnimatorSet()
+ aSet.playTogether(anims)
+ return aSet
+ }
+
+ return null
+ }
+
+ private fun notifyHidePersistentDot(): Animator? {
+ val anims: List<Animator> = listeners.mapNotNull {
+ it.onHidePersistentDot()
+ }
+
+ if (anims.isNotEmpty()) {
+ val aSet = AnimatorSet()
+ aSet.playTogether(anims)
+ return aSet
+ }
+
+ return null
+ }
+
+ private fun notifySystemStart() {
+ listeners.forEach { it.onSystemChromeAnimationStart() }
+ }
+
+ private fun notifySystemFinish() {
+ listeners.forEach { it.onSystemChromeAnimationEnd() }
+ }
+
+ private fun notifySystemAnimationUpdate(anim: ValueAnimator) {
+ listeners.forEach { it.onSystemChromeAnimationUpdate(anim) }
+ }
+
+ override fun addCallback(listener: SystemStatusAnimationCallback) {
+ Assert.isMainThread()
+
+ if (listeners.isEmpty()) {
+ coordinator.startObserving()
+ }
+ listeners.add(listener)
+ }
+
+ override fun removeCallback(listener: SystemStatusAnimationCallback) {
+ Assert.isMainThread()
+
+ listeners.remove(listener)
+ if (listeners.isEmpty()) {
+ coordinator.stopObserving()
+ }
+ }
+
+ private val systemUpdateListener = ValueAnimator.AnimatorUpdateListener {
+ anim -> notifySystemAnimationUpdate(anim)
+ }
+
+ private val systemAnimatorAdapter = object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(p0: Animator?) {
+ notifySystemFinish()
+ }
+
+ override fun onAnimationStart(p0: Animator?) {
+ notifySystemStart()
+ }
+ }
+
+ private val chipUpdateListener = ValueAnimator.AnimatorUpdateListener {
+ anim -> chipAnimationController.onChipAnimationUpdate(anim, animationState)
+ }
+
+ inner class ChipAnimatorAdapter(
+ @SystemAnimationState val endState: Int,
+ val viewCreator: (context: Context) -> View
+ ) : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(p0: Animator?) {
+ chipAnimationController.onChipAnimationEnd(animationState)
+ animationState = endState
+ }
+
+ override fun onAnimationStart(p0: Animator?) {
+ chipAnimationController.onChipAnimationStart(viewCreator, animationState)
+ }
+ }
+}
+
+/**
+ * The general idea here is that this scheduler will run two value animators, and provide
+ * animator-like callbacks for each kind of animation. The SystemChrome animation is expected to
+ * create space for the chip animation to display. This means hiding the system elements in the
+ * status bar and keyguard.
+ *
+ * TODO: the chip animation really only has one client, we can probably remove it from this
+ * interface
+ *
+ * The value animators themselves are simple animators from 0.0 to 1.0. Listeners can apply any
+ * interpolation they choose but realistically these are most likely to be simple alpha transitions
+ */
+interface SystemStatusAnimationCallback {
+ @JvmDefault fun onSystemChromeAnimationUpdate(animator: ValueAnimator) {}
+ @JvmDefault fun onSystemChromeAnimationStart() {}
+ @JvmDefault fun onSystemChromeAnimationEnd() {}
+
+ // Best method name, change my mind
+ @JvmDefault fun onSystemStatusAnimationTransitionToPersistentDot(): Animator? { return null }
+ @JvmDefault fun onHidePersistentDot(): Animator? { return null }
+}
+
+interface SystemStatusChipAnimationCallback {
+ fun onChipAnimationUpdate(animator: ValueAnimator, @SystemAnimationState state: Int) {}
+
+ fun onChipAnimationStart(
+ viewCreator: (context: Context) -> View,
+ @SystemAnimationState state: Int
+ ) {}
+
+ fun onChipAnimationEnd(@SystemAnimationState state: Int) {}
+}
+
+/**
+ */
+@Retention(AnnotationRetention.SOURCE)
+@IntDef(
+ value = [
+ IDLE, ANIMATING_IN, RUNNING_CHIP_ANIM, ANIMATING_OUT
+ ]
+)
+annotation class SystemAnimationState
+
+/** No animation is in progress */
+const val IDLE = 0
+/** System is animating out, and chip is animating in */
+const val ANIMATING_IN = 1
+/** Chip has animated in and is awaiting exit animation, and optionally playing its own animation */
+const val RUNNING_CHIP_ANIM = 2
+/** Chip is animating away and system is animating back */
+const val ANIMATING_OUT = 3
+
+private const val TAG = "SystemStatusAnimationScheduler"
+private const val DELAY: Long = 100
+private const val DISPLAY_LENGTH = 5000L
+private const val ENTRANCE_ANIM_LENGTH = 500L
+private const val CHIP_ANIM_LENGTH = 500L
+private const val MIN_UPTIME: Long = 5 * 1000
+
+private const val DEBUG = false
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationActivityStarter.java
index 5748c4a..2537b19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationActivityStarter.java
@@ -18,6 +18,7 @@
import android.content.Intent;
import android.service.notification.StatusBarNotification;
+import android.view.View;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -33,7 +34,8 @@
void startNotificationGutsIntent(Intent intent, int appUid,
ExpandableNotificationRow row);
- void startHistoryIntent(boolean showHistory);
+ /** Called when the user clicks "Manage" or "History" in the Shade. */
+ void startHistoryIntent(View view, boolean showHistory);
default boolean isCollapsingToShowActivityOverLockscreen() {
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 78fcf18c..f8543f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -170,8 +170,8 @@
}
private void updateColors() {
- mNormalColor = Utils.getColorAttr(mContext, android.R.attr.colorBackground)
- .getDefaultColor();
+ mNormalColor = Utils.getColorAttrDefaultColor(mContext,
+ com.android.internal.R.attr.colorSurface);
mTintedRippleColor = mContext.getColor(
R.color.notification_ripple_tinted_color);
mNormalRippleColor = mContext.getColor(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
index 4ed5056..3bf0ddb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
@@ -106,10 +106,6 @@
showHistory(mShowHistory);
}
- public boolean isButtonVisible() {
- return mManageButton.getAlpha() != 0.0f;
- }
-
@Override
public ExpandableViewState createExpandableViewState() {
return new FooterViewState();
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 733a9f6..751573a 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
@@ -4877,7 +4877,7 @@
clearNotifications(ROWS_ALL, true /* closeShade */);
});
footerView.setManageButtonClickListener(v -> {
- mNotificationActivityStarter.startHistoryIntent(mFooterView.isHistoryShown());
+ mNotificationActivityStarter.startHistoryIntent(v, mFooterView.isHistoryShown());
});
setFooterView(footerView);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index 40e6b40..4e57e44 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -19,10 +19,16 @@
import static android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS;
import static android.app.StatusBarManager.DISABLE_SYSTEM_INFO;
+import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_IN;
+import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_OUT;
+import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.IDLE;
+
+import android.animation.ValueAnimator;
import android.annotation.Nullable;
import android.app.Fragment;
import android.os.Bundle;
import android.os.Parcelable;
+import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
@@ -36,6 +42,9 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.events.PrivacyDotViewController;
+import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
+import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallListener;
@@ -44,6 +53,8 @@
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import org.jetbrains.annotations.NotNull;
+
import java.util.ArrayList;
import java.util.List;
@@ -55,7 +66,8 @@
* updated by the StatusBarIconController and DarkIconManager while it is attached.
*/
public class CollapsedStatusBarFragment extends Fragment implements CommandQueue.Callbacks,
- StatusBarStateController.StateListener {
+ StatusBarStateController.StateListener,
+ SystemStatusAnimationCallback {
public static final String TAG = "CollapsedStatusBarFragment";
private static final String EXTRA_PANEL_STATE = "panel_state";
@@ -78,6 +90,8 @@
private View mOperatorNameFrame;
private CommandQueue mCommandQueue;
private OngoingCallController mOngoingCallController;
+ private final SystemStatusAnimationScheduler mAnimationScheduler;
+ private final PrivacyDotViewController mDotViewController;
private List<String> mBlockedIcons = new ArrayList<>();
@@ -103,8 +117,14 @@
};
@Inject
- public CollapsedStatusBarFragment(OngoingCallController ongoingCallController) {
+ public CollapsedStatusBarFragment(
+ OngoingCallController ongoingCallController,
+ SystemStatusAnimationScheduler animationScheduler,
+ PrivacyDotViewController dotViewController
+ ) {
mOngoingCallController = ongoingCallController;
+ mAnimationScheduler = animationScheduler;
+ mDotViewController = dotViewController;
}
@Override
@@ -127,6 +147,9 @@
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mStatusBar = (PhoneStatusBarView) view;
+ View contents = mStatusBar.findViewById(R.id.status_bar_contents);
+ contents.addOnLayoutChangeListener(mStatusBarLayoutListener);
+ updateStatusBarLocation(contents.getLeft(), contents.getRight());
if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_PANEL_STATE)) {
mStatusBar.restoreHierarchyState(
savedInstanceState.getSparseParcelableArray(EXTRA_PANEL_STATE));
@@ -143,6 +166,7 @@
showClock(false);
initEmergencyCryptkeeperText();
initOperatorName();
+ mAnimationScheduler.addCallback(this);
}
@Override
@@ -208,6 +232,7 @@
if (displayId != getContext().getDisplayId()) {
return;
}
+ Log.d(TAG, "disable: ");
state1 = adjustDisableFlags(state1);
final int old1 = mDisabled1;
final int diff1 = state1 ^ old1;
@@ -292,19 +317,22 @@
return false;
}
- public void hideSystemIconArea(boolean animate) {
+ private void hideSystemIconArea(boolean animate) {
animateHide(mSystemIconArea, animate);
}
- public void showSystemIconArea(boolean animate) {
- animateShow(mSystemIconArea, animate);
+ private void showSystemIconArea(boolean animate) {
+ // Only show the system icon area if we are not currently animating
+ if (mAnimationScheduler.getAnimationState() == IDLE) {
+ animateShow(mSystemIconArea, animate);
+ }
}
- public void hideClock(boolean animate) {
+ private void hideClock(boolean animate) {
animateHiddenState(mClockView, clockHiddenMode(), animate);
}
- public void showClock(boolean animate) {
+ private void showClock(boolean animate) {
animateShow(mClockView, animate);
}
@@ -425,12 +453,60 @@
}
@Override
- public void onStateChanged(int newState) {
-
- }
+ public void onStateChanged(int newState) { }
@Override
public void onDozingChanged(boolean isDozing) {
disable(getContext().getDisplayId(), mDisabled1, mDisabled1, false /* animate */);
}
+
+ @Override
+ public void onSystemChromeAnimationStart() {
+ if (mAnimationScheduler.getAnimationState() == ANIMATING_OUT
+ && !isSystemIconAreaDisabled()) {
+ mSystemIconArea.setVisibility(View.VISIBLE);
+ mSystemIconArea.setAlpha(0f);
+ }
+ }
+
+ @Override
+ public void onSystemChromeAnimationEnd() {
+ // Make sure the system icons are out of the way
+ if (mAnimationScheduler.getAnimationState() == ANIMATING_IN) {
+ mSystemIconArea.setVisibility(View.INVISIBLE);
+ mSystemIconArea.setAlpha(0f);
+ } else {
+ if (isSystemIconAreaDisabled()) {
+ // don't unhide
+ return;
+ }
+
+ mSystemIconArea.setAlpha(1f);
+ mSystemIconArea.setVisibility(View.VISIBLE);
+ }
+ }
+
+ @Override
+ public void onSystemChromeAnimationUpdate(@NotNull ValueAnimator animator) {
+ mSystemIconArea.setAlpha((float) animator.getAnimatedValue());
+ }
+
+ private boolean isSystemIconAreaDisabled() {
+ return (mDisabled1 & DISABLE_SYSTEM_INFO) != 0 || (mDisabled2 & DISABLE2_SYSTEM_ICONS) != 0;
+ }
+
+ private void updateStatusBarLocation(int left, int right) {
+ int leftMargin = left - mStatusBar.getLeft();
+ int rightMargin = mStatusBar.getRight() - right;
+
+ mDotViewController.setStatusBarMargins(leftMargin, rightMargin);
+ }
+
+ // Listen for view end changes of PhoneStatusBarView and publish that to the privacy dot
+ private View.OnLayoutChangeListener mStatusBarLayoutListener =
+ (view, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+ if (left != oldLeft || right != oldRight) {
+ updateStatusBarLocation(left, right);
+ }
+ };
}
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 c3325b1..b83039b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -68,6 +68,7 @@
import android.widget.TextView;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.LockPatternUtils;
@@ -154,6 +155,7 @@
private StatusBar mStatusBar;
private KeyguardAffordanceHelper mAffordanceHelper;
private FalsingManager mFalsingManager;
+ @Nullable private Executor mUiExecutor;
private boolean mUserSetupComplete;
private boolean mPrewarmBound;
private Messenger mPrewarmMessenger;
@@ -429,7 +431,7 @@
}
private void updateWalletVisibility() {
- if (mDozing || !mWalletEnabled) {
+ if (mDozing || !mWalletEnabled || !mHasCard) {
mWalletButton.setVisibility(GONE);
} else {
mWalletButton.setVisibility(VISIBLE);
@@ -659,6 +661,13 @@
updateCameraVisibility();
}
+ @Override
+ public void onKeyguardShowingChanged() {
+ if (mKeyguardStateController.isShowing()) {
+ queryWalletCards();
+ }
+ }
+
private void inflateCameraPreview() {
View previewBefore = mCameraPreview;
boolean visibleBefore = false;
@@ -897,18 +906,20 @@
public void initWallet(QuickAccessWalletClient client, Executor uiExecutor, boolean enabled) {
mQuickAccessWalletClient = client;
mWalletEnabled = enabled && client.isWalletFeatureAvailable();
+ mUiExecutor = uiExecutor;
+ queryWalletCards();
- if (mWalletEnabled) {
- queryWalletCards(uiExecutor);
- }
updateWalletVisibility();
}
- private void queryWalletCards(Executor uiExecutor) {
+ private void queryWalletCards() {
+ if (!mWalletEnabled || mUiExecutor == null) {
+ return;
+ }
GetWalletCardsRequest request =
new GetWalletCardsRequest(1 /* cardWidth */, 1 /* cardHeight */,
1 /* iconSizePx */, 2 /* maxCards */);
- mQuickAccessWalletClient.getWalletCards(uiExecutor, request, mCardRetriever);
+ mQuickAccessWalletClient.getWalletCards(mUiExecutor, request, mCardRetriever);
}
private void onWalletClick(View v) {
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 0694737..c22fec9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -18,7 +18,10 @@
import static com.android.systemui.DejankUtils.whitelistIpcs;
import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
+import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_IN;
+import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_OUT;
+import android.animation.ValueAnimator;
import android.annotation.ColorInt;
import android.content.Context;
import android.content.res.Configuration;
@@ -47,6 +50,8 @@
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
+import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
@@ -64,8 +69,11 @@
/**
* The header group on Keyguard.
*/
-public class KeyguardStatusBarView extends RelativeLayout
- implements BatteryStateChangeCallback, OnUserInfoChangedListener, ConfigurationListener {
+public class KeyguardStatusBarView extends RelativeLayout implements
+ BatteryStateChangeCallback,
+ OnUserInfoChangedListener,
+ ConfigurationListener,
+ SystemStatusAnimationCallback {
private static final int LAYOUT_NONE = 0;
private static final int LAYOUT_CUTOUT = 1;
@@ -96,6 +104,8 @@
private ViewGroup mStatusIconArea;
private int mLayoutState = LAYOUT_NONE;
+ private SystemStatusAnimationScheduler mAnimationScheduler;
+
/**
* Draw this many pixels into the left/right side of the cutout to optimally use the space
*/
@@ -125,6 +135,7 @@
loadDimens();
loadBlockList();
mBatteryController = Dependency.get(BatteryController.class);
+ mAnimationScheduler = Dependency.get(SystemStatusAnimationScheduler.class);
}
@Override
@@ -349,6 +360,7 @@
mIconManager = new TintedIconManager(findViewById(R.id.statusIcons));
mIconManager.setBlockList(mBlockedIcons);
Dependency.get(StatusBarIconController.class).addIconGroup(mIconManager);
+ mAnimationScheduler.addCallback(this);
onThemeChanged();
}
@@ -358,6 +370,7 @@
Dependency.get(UserInfoController.class).removeCallback(this);
Dependency.get(StatusBarIconController.class).removeIconGroup(mIconManager);
Dependency.get(ConfigurationController.class).removeCallback(this);
+ mAnimationScheduler.removeCallback(this);
}
@Override
@@ -509,4 +522,30 @@
mBatteryView.dump(fd, pw, args);
}
}
+
+ /** SystemStatusAnimationCallback */
+ @Override
+ public void onSystemChromeAnimationStart() {
+ if (mAnimationScheduler.getAnimationState() == ANIMATING_OUT) {
+ mSystemIconsContainer.setVisibility(View.VISIBLE);
+ mSystemIconsContainer.setAlpha(0f);
+ }
+ }
+
+ @Override
+ public void onSystemChromeAnimationEnd() {
+ // Make sure the system icons are out of the way
+ if (mAnimationScheduler.getAnimationState() == ANIMATING_IN) {
+ mSystemIconsContainer.setVisibility(View.INVISIBLE);
+ mSystemIconsContainer.setAlpha(0f);
+ } else {
+ mSystemIconsContainer.setAlpha(1f);
+ mSystemIconsContainer.setVisibility(View.VISIBLE);
+ }
+ }
+
+ @Override
+ public void onSystemChromeAnimationUpdate(ValueAnimator anim) {
+ mSystemIconsContainer.setAlpha((float) anim.getAnimatedValue());
+ }
}
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 5aecb72..0c8122c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -666,7 +666,9 @@
pw.println(TAG + ":");
pw.println(" mKeyguardDisplayMode=" + mKeyguardDisplayMode);
pw.println(mCurrentState);
- mNotificationShadeView.getViewRootImpl().dump(" ", pw);
+ if (mNotificationShadeView != null && mNotificationShadeView.getViewRootImpl() != null) {
+ mNotificationShadeView.getViewRootImpl().dump(" ", pw);
+ }
}
@Override
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 d386ebd..43d525d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -208,6 +208,8 @@
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.charging.WiredChargingRippleController;
+import com.android.systemui.statusbar.events.PrivacyDotViewController;
+import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
@@ -426,6 +428,8 @@
private final DemoModeController mDemoModeController;
private NotificationsController mNotificationsController;
private final OngoingCallController mOngoingCallController;
+ private final SystemStatusAnimationScheduler mAnimationScheduler;
+ private final PrivacyDotViewController mDotViewController;
// expanded notifications
// the sliding/resizing panel within the notification window
@@ -794,6 +798,8 @@
BrightnessSlider.Factory brightnessSliderFactory,
WiredChargingRippleController chargingRippleAnimationController,
OngoingCallController ongoingCallController,
+ SystemStatusAnimationScheduler animationScheduler,
+ PrivacyDotViewController dotViewController,
TunerService tunerService,
FeatureFlags featureFlags) {
super(context);
@@ -875,6 +881,8 @@
mBrightnessSliderFactory = brightnessSliderFactory;
mChargingRippleAnimationController = chargingRippleAnimationController;
mOngoingCallController = ongoingCallController;
+ mAnimationScheduler = animationScheduler;
+ mDotViewController = dotViewController;
mFeatureFlags = featureFlags;
tunerService.addTunable(
@@ -1171,7 +1179,10 @@
}).getFragmentManager()
.beginTransaction()
.replace(R.id.status_bar_container,
- new CollapsedStatusBarFragment(mOngoingCallController),
+ new CollapsedStatusBarFragment(
+ mOngoingCallController,
+ mAnimationScheduler,
+ mDotViewController),
CollapsedStatusBarFragment.TAG)
.commit();
@@ -1788,7 +1799,15 @@
@Override
public void startActivity(Intent intent, boolean dismissShade) {
- startActivityDismissingKeyguard(intent, false, dismissShade);
+ startActivityDismissingKeyguard(intent, false /* onlyProvisioned */, dismissShade);
+ }
+
+ @Override
+ public void startActivity(Intent intent, boolean dismissShade,
+ ActivityLaunchAnimator.Controller animationController) {
+ startActivityDismissingKeyguard(intent, false, dismissShade,
+ false /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */,
+ 0 /* flags */, animationController);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 3404528..4356b52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -39,6 +39,7 @@
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.EventLog;
+import android.view.View;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.NotificationVisibility;
@@ -462,7 +463,7 @@
mActivityStarter.dismissKeyguardThenExecute(() -> {
AsyncTask.execute(() -> {
ActivityLaunchAnimator.Controller animationController = null;
- if (!mStatusBar.isOccluded() && mStatusBar.areLaunchAnimationsEnabled()) {
+ if (mStatusBar.areLaunchAnimationsEnabled()) {
animationController = new StatusBarLaunchAnimatorController(
mNotificationAnimationProvider.getAnimatorController(row), mStatusBar,
true /* isActivityIntent */);
@@ -495,7 +496,7 @@
}
@Override
- public void startHistoryIntent(boolean showHistory) {
+ public void startHistoryIntent(View view, boolean showHistory) {
mActivityStarter.dismissKeyguardThenExecute(() -> {
AsyncTask.execute(() -> {
Intent intent = showHistory ? new Intent(
@@ -506,11 +507,27 @@
if (showHistory) {
tsb.addNextIntent(intent);
}
- tsb.startActivities(null, UserHandle.CURRENT);
- // Putting it back on the main thread, since we're touching views
- mMainThreadHandler.post(() -> mCommandQueue.animateCollapsePanels(
- CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */));
+ ActivityLaunchAnimator.Controller animationController = null;
+ if (mStatusBar.areLaunchAnimationsEnabled()) {
+ animationController = new StatusBarLaunchAnimatorController(
+ ActivityLaunchAnimator.Controller.fromView(view), mStatusBar,
+ true /* isActivityIntent */);
+ }
+
+ mActivityLaunchAnimator.startIntentWithAnimation(animationController,
+ (adapter) -> tsb.startActivities(
+ getActivityOptions(mStatusBar.getDisplayId(), adapter),
+ UserHandle.CURRENT));
+
+ // Note that other cases when we should still collapse (like activity already on
+ // top) is handled by the StatusBarLaunchAnimatorController.
+ boolean shouldCollapse = animationController == null;
+ if (shouldCollapse) {
+ // Putting it back on the main thread, since we're touching views
+ mMainThreadHandler.post(() -> mCommandQueue.animateCollapsePanels(
+ CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */));
+ }
});
return true;
}, null, false /* afterKeyguardGone */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 2c2779e..24e6db8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -61,6 +61,8 @@
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.charging.WiredChargingRippleController;
+import com.android.systemui.statusbar.events.PrivacyDotViewController;
+import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
@@ -209,6 +211,8 @@
BrightnessSlider.Factory brightnessSliderFactory,
WiredChargingRippleController chargingRippleAnimationController,
OngoingCallController ongoingCallController,
+ SystemStatusAnimationScheduler animationScheduler,
+ PrivacyDotViewController dotViewController,
TunerService tunerService,
FeatureFlags featureFlags) {
return new StatusBar(
@@ -293,6 +297,8 @@
brightnessSliderFactory,
chargingRippleAnimationController,
ongoingCallController,
+ animationScheduler,
+ dotViewController,
tunerService,
featureFlags);
}
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
index d195062..d1a2c8a 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
@@ -222,6 +222,11 @@
if (mIsDismissed) {
return;
}
+ int cardWidthPx = mCardCarousel.getCardWidthPx();
+ int cardHeightPx = mCardCarousel.getCardHeightPx();
+ if (cardWidthPx == 0 || cardHeightPx == 0) {
+ return;
+ }
if (!mHasRegisteredListener) {
// Listener is registered even when device is locked. Should only be registered once.
mWalletClient.addWalletServiceEventListener(this);
@@ -231,8 +236,6 @@
mWalletView.show();
mWalletView.hideErrorMessage();
int iconSizePx = mContext.getResources().getDimensionPixelSize(R.dimen.wallet_icon_size);
- int cardWidthPx = mCardCarousel.getCardWidthPx();
- int cardHeightPx = mCardCarousel.getCardHeightPx();
GetWalletCardsRequest request =
new GetWalletCardsRequest(cardWidthPx, cardHeightPx, iconSizePx, MAX_CARDS);
mWalletClient.getWalletCards(mExecutor, request, this);
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 74b79d5..81bb819 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -268,6 +268,7 @@
public void onStop() {
mSysUiMainExecutor.execute(() -> {
if (oneHanded.isOneHandedEnabled()) {
+ // Log metrics for 3-button navigation mode.
oneHanded.stopOneHanded(
OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_GESTURE_OUT);
} else if (oneHanded.isSwipeToNotificationEnabled()) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index 59262cf..3252750 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -63,6 +63,7 @@
import com.android.systemui.R.dimen;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.events.PrivacyDotViewController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.settings.FakeSettings;
import com.android.systemui.util.settings.SecureSettings;
@@ -94,6 +95,8 @@
private BroadcastDispatcher mBroadcastDispatcher;
@Mock
private UserTracker mUserTracker;
+ @Mock
+ private PrivacyDotViewController mDotViewController;
@Before
public void setup() {
@@ -116,7 +119,7 @@
mContext.addMockSystemService(DisplayManager.class, mDisplayManager);
mScreenDecorations = spy(new ScreenDecorations(mContext, mMainHandler, mSecureSettings,
- mBroadcastDispatcher, mTunerService, mUserTracker) {
+ mBroadcastDispatcher, mTunerService, mUserTracker, mDotViewController) {
@Override
public void start() {
super.start();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
index 3f0831c..78c6717 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
@@ -233,9 +233,9 @@
TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME,
AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
assertEquals(2,
- mController.getActiveAppOpsForUser(UserHandle.getUserId(TEST_UID)).size());
- assertEquals(1,
- mController.getActiveAppOpsForUser(UserHandle.getUserId(TEST_UID_OTHER)).size());
+ mController.getActiveAppOpsForUser(UserHandle.getUserId(TEST_UID), false).size());
+ assertEquals(1, mController.getActiveAppOpsForUser(UserHandle.getUserId(TEST_UID_OTHER),
+ false).size());
}
@Test
@@ -245,11 +245,11 @@
mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO,
TEST_UID_NON_USER_SENSITIVE, mExemptedRolePkgName, true);
assertEquals(0, mController.getActiveAppOpsForUser(
- UserHandle.getUserId(TEST_UID_NON_USER_SENSITIVE)).size());
+ UserHandle.getUserId(TEST_UID_NON_USER_SENSITIVE), false).size());
mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO,
TEST_UID_NON_USER_SENSITIVE, SYSTEM_PKG, true);
assertEquals(0, mController.getActiveAppOpsForUser(
- UserHandle.getUserId(TEST_UID_NON_USER_SENSITIVE)).size());
+ UserHandle.getUserId(TEST_UID_NON_USER_SENSITIVE), false).size());
}
@Test
@@ -441,7 +441,19 @@
}
@Test
- public void testOnlyRecordAudioPaused() {
+ public void testPausedPhoneCallMicrophoneFilteredOut() {
+ mController.addCallback(new int[]{AppOpsManager.OP_PHONE_CALL_MICROPHONE}, mCallback);
+ mTestableLooper.processAllMessages();
+
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_PHONE_CALL_MICROPHONE, TEST_UID, TEST_PACKAGE_NAME, true);
+ mTestableLooper.processAllMessages();
+
+ assertTrue(mController.getActiveAppOps().isEmpty());
+ }
+
+ @Test
+ public void testOnlyRecordAudioPhoneCallMicrophonePaused() {
mController.addCallback(new int[]{
AppOpsManager.OP_RECORD_AUDIO,
AppOpsManager.OP_CAMERA
@@ -532,6 +544,40 @@
}
@Test
+ public void testPhoneCallMicrophoneFilteredWhenMicDisabled() {
+ mController.addCallback(
+ new int[]{AppOpsManager.OP_PHONE_CALL_MICROPHONE, AppOpsManager.OP_CAMERA},
+ mCallback);
+ mTestableLooper.processAllMessages();
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_PHONE_CALL_MICROPHONE, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
+ mTestableLooper.processAllMessages();
+ List<AppOpItem> list = mController.getActiveAppOps();
+ assertEquals(1, list.size());
+ assertEquals(AppOpsManager.OP_PHONE_CALL_MICROPHONE, list.get(0).getCode());
+ assertFalse(list.get(0).isDisabled());
+
+ // Add a camera op, and disable the microphone. The camera op should be the only op returned
+ mController.onSensorBlockedChanged(MICROPHONE, true);
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
+ mTestableLooper.processAllMessages();
+ list = mController.getActiveAppOps();
+ assertEquals(1, list.size());
+ assertEquals(AppOpsManager.OP_CAMERA, list.get(0).getCode());
+
+
+ // Re enable the microphone, and verify the op returns
+ mController.onSensorBlockedChanged(MICROPHONE, false);
+ mTestableLooper.processAllMessages();
+
+ list = mController.getActiveAppOps();
+ assertEquals(2, list.size());
+ int micIdx = list.get(0).getCode() == AppOpsManager.OP_CAMERA ? 1 : 0;
+ assertEquals(AppOpsManager.OP_PHONE_CALL_MICROPHONE, list.get(micIdx).getCode());
+ }
+
+ @Test
public void testCameraFilteredWhenCameraDisabled() {
mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_CAMERA},
mCallback);
@@ -563,6 +609,39 @@
assertEquals(AppOpsManager.OP_CAMERA, list.get(cameraIdx).getCode());
}
+ @Test
+ public void testPhoneCallCameraFilteredWhenCameraDisabled() {
+ mController.addCallback(
+ new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_PHONE_CALL_CAMERA},
+ mCallback);
+ mTestableLooper.processAllMessages();
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_PHONE_CALL_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
+ mTestableLooper.processAllMessages();
+ List<AppOpItem> list = mController.getActiveAppOps();
+ assertEquals(1, list.size());
+ assertEquals(AppOpsManager.OP_PHONE_CALL_CAMERA, list.get(0).getCode());
+ assertFalse(list.get(0).isDisabled());
+
+ // Add an audio op, and disable the camera. The audio op should be the only op returned
+ mController.onSensorBlockedChanged(CAMERA, true);
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
+ mTestableLooper.processAllMessages();
+ list = mController.getActiveAppOps();
+ assertEquals(1, list.size());
+ assertEquals(AppOpsManager.OP_RECORD_AUDIO, list.get(0).getCode());
+
+ // Re enable the camera, and verify the op returns
+ mController.onSensorBlockedChanged(CAMERA, false);
+ mTestableLooper.processAllMessages();
+
+ list = mController.getActiveAppOps();
+ assertEquals(2, list.size());
+ int cameraIdx = list.get(0).getCode() == AppOpsManager.OP_PHONE_CALL_CAMERA ? 0 : 1;
+ assertEquals(AppOpsManager.OP_PHONE_CALL_CAMERA, list.get(cameraIdx).getCode());
+ }
+
private class TestHandler extends AppOpsControllerImpl.H {
TestHandler(Looper looper) {
mController.super(looper);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java
index 42e88b0..63ce98a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java
@@ -22,6 +22,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import android.app.IWallpaperManager;
import android.os.PowerManager;
import android.testing.AndroidTestingRunner;
@@ -43,9 +44,12 @@
private WakefulnessLifecycle mWakefulness;
private WakefulnessLifecycle.Observer mWakefulnessObserver;
+ private IWallpaperManager mWallpaperManager;
+
@Before
public void setUp() throws Exception {
- mWakefulness = new WakefulnessLifecycle();
+ mWallpaperManager = mock(IWallpaperManager.class);
+ mWakefulness = new WakefulnessLifecycle(mContext, mWallpaperManager);
mWakefulnessObserver = mock(WakefulnessLifecycle.Observer.class);
mWakefulness.addObserver(mWakefulnessObserver);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
index 0ce03ad..81ca4c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
@@ -22,8 +22,6 @@
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.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
@@ -35,10 +33,7 @@
import android.app.INotificationManager;
import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
import android.app.Person;
-import android.app.people.ConversationChannel;
import android.app.people.IPeopleManager;
import android.app.people.PeopleSpaceTile;
import android.appwidget.AppWidgetManager;
@@ -47,7 +42,6 @@
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
-import android.content.pm.ParceledListSlice;
import android.content.pm.ShortcutInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -57,7 +51,6 @@
import android.os.Bundle;
import android.os.UserHandle;
import android.provider.ContactsContract;
-import android.service.notification.ConversationChannelWrapper;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.util.DisplayMetrics;
@@ -81,10 +74,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.Arrays;
import java.util.List;
import java.util.Map;
-import java.util.stream.Collectors;
@RunWith(AndroidTestingRunner.class)
@SmallTest
@@ -185,8 +176,6 @@
@Mock
private IPeopleManager mPeopleManager;
@Mock
- private LauncherApps mLauncherApps;
- @Mock
private IAppWidgetService mIAppWidgetService;
@Mock
private AppWidgetManager mAppWidgetManager;
@@ -239,84 +228,6 @@
}
@Test
- public void testGetRecentTilesReturnsSortedListWithOnlyRecentConversations() throws Exception {
- // Ensure the less-recent Important conversation is before more recent conversations.
- ConversationChannelWrapper newerNonImportantConversation = getConversationChannelWrapper(
- SHORTCUT_ID_1, false, 3);
- ConversationChannelWrapper newerImportantConversation = getConversationChannelWrapper(
- SHORTCUT_ID_1 + 1, true, 3);
- ConversationChannelWrapper olderImportantConversation = getConversationChannelWrapper(
- SHORTCUT_ID_1 + 2,
- true, 1);
- when(mNotificationManager.getConversations(anyBoolean())).thenReturn(
- new ParceledListSlice(Arrays.asList(
- newerNonImportantConversation, newerImportantConversation,
- olderImportantConversation)));
-
- // Ensure the non-Important conversation is sorted between these recent conversations.
- ConversationChannel recentConversationBeforeNonImportantConversation =
- getConversationChannel(
- SHORTCUT_ID_1 + 3, 4);
- ConversationChannel recentConversationAfterNonImportantConversation =
- getConversationChannel(SHORTCUT_ID_1 + 4,
- 2);
- when(mPeopleManager.getRecentConversations()).thenReturn(
- new ParceledListSlice(Arrays.asList(recentConversationAfterNonImportantConversation,
- recentConversationBeforeNonImportantConversation)));
-
- List<String> orderedShortcutIds = PeopleSpaceUtils.getRecentTiles(
- mContext, mNotificationManager, mPeopleManager,
- mLauncherApps, mNotificationEntryManager)
- .stream().map(tile -> tile.getId()).collect(Collectors.toList());
-
- // Check for sorted recent conversations.
- assertThat(orderedShortcutIds).containsExactly(
- recentConversationBeforeNonImportantConversation.getShortcutInfo().getId(),
- newerNonImportantConversation.getShortcutInfo().getId(),
- recentConversationAfterNonImportantConversation.getShortcutInfo().getId())
- .inOrder();
- }
-
- @Test
- public void testGetPriorityTilesReturnsSortedListWithOnlyImportantConversations()
- throws Exception {
- // Ensure the less-recent Important conversation is before more recent conversations.
- ConversationChannelWrapper newerNonImportantConversation = getConversationChannelWrapper(
- SHORTCUT_ID_1, false, 3);
- ConversationChannelWrapper newerImportantConversation = getConversationChannelWrapper(
- SHORTCUT_ID_1 + 1, true, 3);
- ConversationChannelWrapper olderImportantConversation = getConversationChannelWrapper(
- SHORTCUT_ID_1 + 2,
- true, 1);
- when(mNotificationManager.getConversations(anyBoolean())).thenReturn(
- new ParceledListSlice(Arrays.asList(
- newerNonImportantConversation, newerImportantConversation,
- olderImportantConversation)));
-
- // Ensure the non-Important conversation is sorted between these recent conversations.
- ConversationChannel recentConversationBeforeNonImportantConversation =
- getConversationChannel(
- SHORTCUT_ID_1 + 3, 4);
- ConversationChannel recentConversationAfterNonImportantConversation =
- getConversationChannel(SHORTCUT_ID_1 + 4,
- 2);
- when(mPeopleManager.getRecentConversations()).thenReturn(
- new ParceledListSlice(Arrays.asList(recentConversationAfterNonImportantConversation,
- recentConversationBeforeNonImportantConversation)));
-
- List<String> orderedShortcutIds = PeopleSpaceUtils.getPriorityTiles(
- mContext, mNotificationManager, mPeopleManager,
- mLauncherApps, mNotificationEntryManager)
- .stream().map(tile -> tile.getId()).collect(Collectors.toList());
-
- // Check for sorted priority conversations.
- assertThat(orderedShortcutIds).containsExactly(
- newerImportantConversation.getShortcutInfo().getId(),
- olderImportantConversation.getShortcutInfo().getId())
- .inOrder();
- }
-
- @Test
public void testGetMessagingStyleMessagesNoMessage() {
Notification notification = new Notification.Builder(mContext, "test")
.setContentTitle("TEST_TITLE")
@@ -570,30 +481,4 @@
verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
any());
}
-
- private ConversationChannelWrapper getConversationChannelWrapper(String shortcutId,
- boolean importantConversation, long lastInteractionTimestamp) throws Exception {
- ConversationChannelWrapper convo = new ConversationChannelWrapper();
- NotificationChannel notificationChannel = new NotificationChannel(shortcutId,
- "channel" + shortcutId,
- NotificationManager.IMPORTANCE_DEFAULT);
- notificationChannel.setImportantConversation(importantConversation);
- convo.setNotificationChannel(notificationChannel);
- convo.setShortcutInfo(new ShortcutInfo.Builder(mContext, shortcutId).setLongLabel(
- "name").build());
- when(mPeopleManager.getLastInteraction(anyString(), anyInt(),
- eq(shortcutId))).thenReturn(lastInteractionTimestamp);
- return convo;
- }
-
- private ConversationChannel getConversationChannel(String shortcutId,
- long lastInteractionTimestamp) throws Exception {
- ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(mContext, shortcutId).setLongLabel(
- "name").build();
- ConversationChannel convo = new ConversationChannel(shortcutInfo, 0, null, null,
- lastInteractionTimestamp, false);
- when(mPeopleManager.getLastInteraction(anyString(), anyInt(),
- eq(shortcutId))).thenReturn(lastInteractionTimestamp);
- return convo;
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
index 107ac83..3cc55f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
@@ -114,8 +114,6 @@
when(mMockContext.getString(R.string.birthday_status)).thenReturn(
mContext.getString(R.string.birthday_status));
- when(mMockContext.getString(R.string.basic_status)).thenReturn(
- mContext.getString(R.string.basic_status));
when(mMockContext.getPackageManager()).thenReturn(mPackageManager);
when(mMockContext.getString(R.string.over_timestamp)).thenReturn(
mContext.getString(R.string.over_timestamp));
@@ -126,7 +124,6 @@
when(resources.getConfiguration()).thenReturn(configuration);
when(resources.getDisplayMetrics()).thenReturn(displayMetrics);
TextView textView = mock(TextView.class);
- // when(new TextView(mMockContext)).thenReturn(textView);
when(textView.getLineHeight()).thenReturn(16);
when(mPackageManager.getApplicationIcon(anyString())).thenReturn(null);
mPeopleTileViewHelper = new PeopleTileViewHelper(mContext,
@@ -134,16 +131,41 @@
}
@Test
- public void testCreateRemoteViewsWithLastInteractionTime() {
+ public void testCreateRemoteViewsWithLastInteractionTimeUnderOneDayHidden() {
RemoteViews views = new PeopleTileViewHelper(mContext,
PERSON_TILE_WITHOUT_NOTIFICATION, 0, mOptions).getViews();
View result = views.apply(mContext, null);
+ // Not showing last interaction.
+ assertEquals(View.GONE, result.findViewById(R.id.last_interaction).getVisibility());
+
+ mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,
+ getSizeInDp(R.dimen.required_width_for_large));
+ mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,
+ getSizeInDp(R.dimen.required_height_for_large));
+ RemoteViews largeView = new PeopleTileViewHelper(mContext,
+ PERSON_TILE_WITHOUT_NOTIFICATION, 0, mOptions).getViews();
+ View largeResult = largeView.apply(mContext, null);
+
+ // Not showing last interaction.
+ assertEquals(View.GONE, largeResult.findViewById(R.id.last_interaction).getVisibility());
+ }
+
+ @Test
+ public void testCreateRemoteViewsWithLastInteractionTime() {
+ PeopleSpaceTile tileWithLastInteraction =
+ PERSON_TILE_WITHOUT_NOTIFICATION.toBuilder().setLastInteractionTimestamp(
+ 123445L).build();
+ RemoteViews views = new PeopleTileViewHelper(mContext,
+ tileWithLastInteraction, 0, mOptions).getViews();
+ View result = views.apply(mContext, null);
+
TextView name = (TextView) result.findViewById(R.id.name);
assertEquals(name.getText(), NAME);
// Has last interaction.
+ assertEquals(View.VISIBLE, result.findViewById(R.id.last_interaction).getVisibility());
TextView lastInteraction = (TextView) result.findViewById(R.id.last_interaction);
- assertEquals(lastInteraction.getText(), mContext.getString(R.string.basic_status));
+ assertEquals(lastInteraction.getText(), "Over 2 weeks ago");
// No availability.
assertEquals(View.GONE, result.findViewById(R.id.availability).getVisibility());
// Shows person icon.
@@ -154,7 +176,7 @@
mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,
getSizeInDp(R.dimen.required_width_for_medium) - 1);
RemoteViews smallView = new PeopleTileViewHelper(mContext,
- PERSON_TILE_WITHOUT_NOTIFICATION, 0, mOptions).getViews();
+ tileWithLastInteraction, 0, mOptions).getViews();
View smallResult = smallView.apply(mContext, null);
// Show name over predefined icon.
@@ -171,14 +193,15 @@
mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,
getSizeInDp(R.dimen.required_height_for_large));
RemoteViews largeView = new PeopleTileViewHelper(mContext,
- PERSON_TILE_WITHOUT_NOTIFICATION, 0, mOptions).getViews();
+ tileWithLastInteraction, 0, mOptions).getViews();
View largeResult = largeView.apply(mContext, null);
name = (TextView) largeResult.findViewById(R.id.name);
assertEquals(name.getText(), NAME);
// Has last interaction.
+ assertEquals(View.VISIBLE, largeResult.findViewById(R.id.last_interaction).getVisibility());
lastInteraction = (TextView) result.findViewById(R.id.last_interaction);
- assertEquals(lastInteraction.getText(), mContext.getString(R.string.basic_status));
+ assertEquals(lastInteraction.getText(), "Over 2 weeks ago");
// No availability.
assertEquals(View.GONE, result.findViewById(R.id.availability).getVisibility());
// Shows person icon.
@@ -202,8 +225,7 @@
TextView name = (TextView) result.findViewById(R.id.name);
assertEquals(name.getText(), NAME);
// Has last interaction over status.
- TextView lastInteraction = (TextView) result.findViewById(R.id.last_interaction);
- assertEquals(lastInteraction.getText(), mContext.getString(R.string.basic_status));
+ assertEquals(View.GONE, result.findViewById(R.id.last_interaction).getVisibility());
// Has availability.
assertEquals(View.VISIBLE, result.findViewById(R.id.availability).getVisibility());
// Has person icon.
@@ -237,14 +259,13 @@
name = (TextView) largeResult.findViewById(R.id.name);
assertEquals(name.getText(), NAME);
// Has last interaction.
- lastInteraction = (TextView) result.findViewById(R.id.last_interaction);
- assertEquals(lastInteraction.getText(), mContext.getString(R.string.basic_status));
+ assertEquals(View.GONE, largeResult.findViewById(R.id.last_interaction).getVisibility());
// Has availability.
- assertEquals(View.VISIBLE, result.findViewById(R.id.availability).getVisibility());
+ assertEquals(View.VISIBLE, largeResult.findViewById(R.id.availability).getVisibility());
// Shows person icon.
- assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility());
+ assertEquals(View.VISIBLE, largeResult.findViewById(R.id.person_icon).getVisibility());
// No status.
- assertThat((View) result.findViewById(R.id.text_content)).isNull();
+ assertThat((View) largeResult.findViewById(R.id.text_content)).isNull();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java
index 0ef3ca2..ccb40e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java
@@ -29,6 +29,7 @@
import android.content.Intent;
import android.os.Bundle;
import android.os.UserHandle;
+import android.os.UserManager;
import android.service.notification.NotificationListenerService;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
@@ -83,6 +84,8 @@
private BubblesManager mBubblesManager;
@Mock
private NotificationListenerService.Ranking mRanking;
+ @Mock
+ private UserManager mUserManager;
@Captor
private ArgumentCaptor<NotificationVisibility> mNotificationVisibilityCaptor;
@@ -93,7 +96,7 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mActivity = new LaunchConversationActivity(mNotificationEntryManager,
- Optional.of(mBubblesManager));
+ Optional.of(mBubblesManager), mUserManager);
mActivity.setIsForTesting(true, mIStatusBarService);
mIntent = new Intent();
mIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID, "tile ID");
@@ -113,6 +116,7 @@
when(mNotifEntryCanBubble.canBubble()).thenReturn(true);
when(mNotifEntryNoRanking.getRanking()).thenReturn(null);
when(mRanking.getRank()).thenReturn(NOTIF_RANK);
+ when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(false);
}
@Test
@@ -176,4 +180,18 @@
anyInt(), any(), anyInt(), anyInt(), any());
verify(mBubblesManager, times(1)).expandStackAndSelectBubble(eq(mNotifEntryCanBubble));
}
+
+ @Test
+ public void testQuietModeOpensQuietModeDialog() throws Exception {
+ mIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_NOTIFICATION_KEY,
+ NOTIF_KEY);
+ when(mUserManager.isQuietModeEnabled(eq(USER_HANDLE))).thenReturn(true);
+ mActivity.setIntent(mIntent);
+ mActivity.onCreate(new Bundle());
+
+ assertThat(mActivity.isFinishing()).isTrue();
+ verify(mIStatusBarService, never()).onNotificationClear(any(),
+ anyInt(), any(), anyInt(), anyInt(), any());
+ verify(mBubblesManager, never()).expandStackAndSelectBubble(any());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
index 7125500..e9be8d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
@@ -35,7 +35,9 @@
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.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -45,8 +47,10 @@
import static java.util.Objects.requireNonNull;
+import android.app.INotificationManager;
import android.app.Notification;
import android.app.NotificationChannel;
+import android.app.NotificationManager;
import android.app.Person;
import android.app.people.ConversationChannel;
import android.app.people.ConversationStatus;
@@ -59,11 +63,14 @@
import android.content.SharedPreferences;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
import android.content.pm.ShortcutInfo;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Bundle;
import android.os.UserHandle;
+import android.os.UserManager;
+import android.service.notification.ConversationChannelWrapper;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
@@ -95,6 +102,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -169,6 +177,10 @@
private NotificationEntryManager mNotificationEntryManager;
@Mock
private PackageManager mPackageManager;
+ @Mock
+ private INotificationManager mNotificationManager;
+ @Mock
+ private UserManager mUserManager;
@Captor
private ArgumentCaptor<NotificationHandler> mListenerCaptor;
@@ -189,7 +201,8 @@
mProvider = new PeopleSpaceWidgetProvider();
mProvider.setPeopleSpaceWidgetManager(mManager);
mManager.setAppWidgetManager(mAppWidgetManager, mIPeopleManager, mPeopleManager,
- mLauncherApps, mNotificationEntryManager, mPackageManager, true, mProvider);
+ mLauncherApps, mNotificationEntryManager, mPackageManager, true, mProvider,
+ mUserManager, mNotificationManager);
mManager.attach(mListenerService);
verify(mListenerService).addNotificationHandler(mListenerCaptor.capture());
@@ -201,6 +214,98 @@
addTileForWidget(PERSON_TILE_WITH_SAME_URI, WIDGET_ID_WITH_SAME_URI);
when(mAppWidgetManager.getAppWidgetOptions(eq(WIDGET_ID_WITHOUT_SHORTCUT)))
.thenReturn(new Bundle());
+ when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
+ }
+
+ @Test
+ public void testGetRecentTilesReturnsSortedListWithOnlyRecentConversations() throws Exception {
+ // Ensure the less-recent Important conversation is before more recent conversations.
+ ConversationChannelWrapper newerNonImportantConversation = getConversationChannelWrapper(
+ SHORTCUT_ID, false, 3);
+ ConversationChannelWrapper newerImportantConversation = getConversationChannelWrapper(
+ SHORTCUT_ID + 1, true, 3);
+ ConversationChannelWrapper olderImportantConversation = getConversationChannelWrapper(
+ SHORTCUT_ID + 2,
+ true, 1);
+ when(mNotificationManager.getConversations(anyBoolean())).thenReturn(
+ new ParceledListSlice(Arrays.asList(
+ newerNonImportantConversation, newerImportantConversation,
+ olderImportantConversation)));
+
+ // Ensure the non-Important conversation is sorted between these recent conversations.
+ ConversationChannel recentConversationBeforeNonImportantConversation =
+ getConversationChannel(
+ SHORTCUT_ID + 3, 4);
+ ConversationChannel recentConversationAfterNonImportantConversation =
+ getConversationChannel(SHORTCUT_ID + 4,
+ 2);
+ when(mIPeopleManager.getRecentConversations()).thenReturn(
+ new ParceledListSlice(Arrays.asList(recentConversationAfterNonImportantConversation,
+ recentConversationBeforeNonImportantConversation)));
+
+ List<String> orderedShortcutIds = mManager.getRecentTiles()
+ .stream().map(tile -> tile.getId()).collect(Collectors.toList());
+
+ // Check for sorted recent conversations.
+ assertThat(orderedShortcutIds).containsExactly(
+ recentConversationBeforeNonImportantConversation.getShortcutInfo().getId(),
+ newerNonImportantConversation.getShortcutInfo().getId(),
+ recentConversationAfterNonImportantConversation.getShortcutInfo().getId())
+ .inOrder();
+ }
+
+ @Test
+ public void testGetPriorityTilesReturnsSortedListWithOnlyImportantConversations()
+ throws Exception {
+ // Ensure the less-recent Important conversation is before more recent conversations.
+ ConversationChannelWrapper newerNonImportantConversation = getConversationChannelWrapper(
+ SHORTCUT_ID, false, 3);
+ ConversationChannelWrapper newerImportantConversation = getConversationChannelWrapper(
+ SHORTCUT_ID + 1, true, 3);
+ ConversationChannelWrapper olderImportantConversation = getConversationChannelWrapper(
+ SHORTCUT_ID + 2,
+ true, 1);
+ when(mNotificationManager.getConversations(anyBoolean())).thenReturn(
+ new ParceledListSlice(Arrays.asList(
+ newerNonImportantConversation, newerImportantConversation,
+ olderImportantConversation)));
+
+ List<String> orderedShortcutIds = mManager.getPriorityTiles()
+ .stream().map(tile -> tile.getId()).collect(Collectors.toList());
+
+ // Check for sorted priority conversations.
+ assertThat(orderedShortcutIds).containsExactly(
+ newerImportantConversation.getShortcutInfo().getId(),
+ olderImportantConversation.getShortcutInfo().getId())
+ .inOrder();
+ }
+
+ @Test
+ public void testGetTilesReturnsNothingInQuietMode()
+ throws Exception {
+ // Ensure the less-recent Important conversation is before more recent conversations.
+ ConversationChannelWrapper newerNonImportantConversation = getConversationChannelWrapper(
+ SHORTCUT_ID, false, 3);
+ ConversationChannelWrapper newerImportantConversation = getConversationChannelWrapper(
+ SHORTCUT_ID + 1, true, 3);
+ ConversationChannelWrapper olderImportantConversation = getConversationChannelWrapper(
+ SHORTCUT_ID + 2,
+ true, 1);
+ when(mNotificationManager.getConversations(anyBoolean())).thenReturn(
+ new ParceledListSlice(Arrays.asList(
+ newerNonImportantConversation, newerImportantConversation,
+ olderImportantConversation)));
+ ConversationChannel recentConversation =
+ getConversationChannel(
+ SHORTCUT_ID + 3, 4);
+ when(mIPeopleManager.getRecentConversations()).thenReturn(
+ new ParceledListSlice(Arrays.asList(recentConversation)));
+
+ when(mUserManager.isQuietModeEnabled(any())).thenReturn(true);
+
+ // Check nothing returned.
+ assertThat(mManager.getPriorityTiles()).isEmpty();
+ assertThat(mManager.getRecentTiles()).isEmpty();
}
@Test
@@ -1208,4 +1313,30 @@
editor.putStringSet(contactUri.toString(), storedWidgetIdsByUri);
editor.apply();
}
+
+ private ConversationChannelWrapper getConversationChannelWrapper(String shortcutId,
+ boolean importantConversation, long lastInteractionTimestamp) throws Exception {
+ ConversationChannelWrapper convo = new ConversationChannelWrapper();
+ NotificationChannel notificationChannel = new NotificationChannel(shortcutId,
+ "channel" + shortcutId,
+ NotificationManager.IMPORTANCE_DEFAULT);
+ notificationChannel.setImportantConversation(importantConversation);
+ convo.setNotificationChannel(notificationChannel);
+ convo.setShortcutInfo(new ShortcutInfo.Builder(mContext, shortcutId).setLongLabel(
+ "name").build());
+ when(mIPeopleManager.getLastInteraction(anyString(), anyInt(),
+ eq(shortcutId))).thenReturn(lastInteractionTimestamp);
+ return convo;
+ }
+
+ private ConversationChannel getConversationChannel(String shortcutId,
+ long lastInteractionTimestamp) throws Exception {
+ ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(mContext, shortcutId).setLongLabel(
+ "name").build();
+ ConversationChannel convo = new ConversationChannel(shortcutInfo, 0, null, null,
+ lastInteractionTimestamp, false);
+ when(mIPeopleManager.getLastInteraction(anyString(), anyInt(),
+ eq(shortcutId))).thenReturn(lastInteractionTimestamp);
+ return convo;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
index 791dd12..05a1e4f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
@@ -28,6 +28,7 @@
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.appops.AppOpsController
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.privacy.logging.PrivacyLogger
import com.android.systemui.settings.UserTracker
@@ -43,6 +44,7 @@
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Captor
@@ -86,6 +88,8 @@
private lateinit var privacyLogger: PrivacyLogger
@Mock
private lateinit var keyguardStateController: KeyguardStateController
+ @Mock
+ private lateinit var appOpsController: AppOpsController
@Captor
private lateinit var dialogDismissedCaptor: ArgumentCaptor<PrivacyDialog.OnDialogDismissed>
@Captor
@@ -131,6 +135,7 @@
uiExecutor,
privacyLogger,
keyguardStateController,
+ appOpsController,
dialogProvider
)
}
@@ -143,18 +148,27 @@
}
@Test
+ fun testMicMutedParameter() {
+ `when`(appOpsController.isMicMuted).thenReturn(true)
+ controller.showDialog(context)
+ backgroundExecutor.runAllReady()
+
+ verify(permissionManager).getIndicatorAppOpUsageData(true)
+ }
+
+ @Test
fun testPermissionManagerOnlyCalledInBackgroundThread() {
controller.showDialog(context)
- verify(permissionManager, never()).indicatorAppOpUsageData
+ verify(permissionManager, never()).getIndicatorAppOpUsageData(anyBoolean())
backgroundExecutor.runAllReady()
- verify(permissionManager).indicatorAppOpUsageData
+ verify(permissionManager).getIndicatorAppOpUsageData(anyBoolean())
}
@Test
fun testPackageManagerOnlyCalledInBackgroundThread() {
val usage = createMockPermGroupUsage()
`when`(usage.isPhoneCall).thenReturn(false)
- `when`(permissionManager.indicatorAppOpUsageData).thenReturn(listOf(usage))
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
controller.showDialog(context)
verify(packageManager, never()).getApplicationInfoAsUser(anyString(), anyInt(), anyInt())
@@ -217,7 +231,7 @@
isPhoneCall = false,
attribution = TEST_ATTRIBUTION
)
- `when`(permissionManager.indicatorAppOpUsageData).thenReturn(listOf(usage))
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
controller.showDialog(context)
exhaustExecutors()
@@ -246,7 +260,7 @@
packageName = "${TEST_PACKAGE_NAME}_microphone",
permGroupName = PERM_MICROPHONE
)
- `when`(permissionManager.indicatorAppOpUsageData).thenReturn(
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
listOf(usage_microphone, usage_camera)
)
@@ -269,7 +283,7 @@
packageName = "${TEST_PACKAGE_NAME}_recent",
isActive = false
)
- `when`(permissionManager.indicatorAppOpUsageData).thenReturn(
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
listOf(usage_recent, usage_active)
)
@@ -292,7 +306,7 @@
isActive = true,
lastAccess = 1L
)
- `when`(permissionManager.indicatorAppOpUsageData).thenReturn(
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
listOf(usage_active, usage_active_moreRecent)
)
controller.showDialog(context)
@@ -319,7 +333,7 @@
isActive = false,
lastAccess = 2L
)
- `when`(permissionManager.indicatorAppOpUsageData).thenReturn(
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
listOf(usage_recent, usage_mostRecent, usage_moreRecent)
)
@@ -342,7 +356,7 @@
permGroupName = PERM_LOCATION
)
- `when`(permissionManager.indicatorAppOpUsageData).thenReturn(
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
listOf(usage_camera, usage_location, usage_microphone)
)
`when`(privacyItemController.micCameraAvailable).thenReturn(false)
@@ -366,7 +380,7 @@
permGroupName = PERM_LOCATION
)
- `when`(permissionManager.indicatorAppOpUsageData).thenReturn(
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
listOf(usage_camera, usage_location, usage_microphone)
)
`when`(privacyItemController.locationAvailable).thenReturn(false)
@@ -392,7 +406,7 @@
permGroupName = PERM_LOCATION
)
- `when`(permissionManager.indicatorAppOpUsageData).thenReturn(
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
listOf(usage_camera, usage_location, usage_microphone)
)
`when`(privacyItemController.micCameraAvailable).thenReturn(true)
@@ -416,7 +430,7 @@
permGroupName = PERM_LOCATION
)
- `when`(permissionManager.indicatorAppOpUsageData).thenReturn(
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
listOf(usage_camera, usage_location, usage_microphone)
)
`when`(privacyItemController.micCameraAvailable).thenReturn(false)
@@ -433,7 +447,8 @@
val usage_enterprise = createMockPermGroupUsage(
uid = generateUidForUser(ENT_USER_ID)
)
- `when`(permissionManager.indicatorAppOpUsageData).thenReturn(listOf(usage_enterprise))
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean()))
+ .thenReturn(listOf(usage_enterprise))
controller.showDialog(context)
exhaustExecutors()
@@ -446,7 +461,8 @@
val usage_other = createMockPermGroupUsage(
uid = generateUidForUser(ENT_USER_ID + 1)
)
- `when`(permissionManager.indicatorAppOpUsageData).thenReturn(listOf(usage_other))
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean()))
+ .thenReturn(listOf(usage_other))
controller.showDialog(context)
exhaustExecutors()
@@ -514,7 +530,8 @@
}
private fun setUpDefaultMockResponses() {
- `when`(permissionManager.indicatorAppOpUsageData).thenReturn(emptyList())
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(emptyList())
+ `when`(appOpsController.isMicMuted).thenReturn(false)
`when`(packageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
.thenAnswer {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
index bba1c6a..e4d7b1b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
@@ -46,7 +46,7 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
-import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyList
import org.mockito.Captor
import org.mockito.Mock
@@ -156,7 +156,7 @@
fun testDistinctItems() {
doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 0),
AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 0)))
- .`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+ .`when`(appOpsController).getActiveAppOps(anyBoolean())
privacyItemController.addCallback(callback)
executor.runAllReady()
@@ -168,7 +168,7 @@
fun testSimilarItemsDifferentTimeStamp() {
doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 0),
AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 1)))
- .`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+ .`when`(appOpsController).getActiveAppOps(anyBoolean())
privacyItemController.addCallback(callback)
executor.runAllReady()
@@ -215,7 +215,7 @@
@Test
fun testMultipleCallbacksAreUpdated() {
- doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+ doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOps(anyBoolean())
val otherCallback = mock(PrivacyItemController.Callback::class.java)
privacyItemController.addCallback(callback)
@@ -233,7 +233,7 @@
@Test
fun testRemoveCallback() {
- doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+ doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOps(anyBoolean())
val otherCallback = mock(PrivacyItemController.Callback::class.java)
privacyItemController.addCallback(callback)
privacyItemController.addCallback(otherCallback)
@@ -254,7 +254,7 @@
fun testListShouldNotHaveNull() {
doReturn(listOf(AppOpItem(AppOpsManager.OP_ACTIVATE_VPN, TEST_UID, "", 0),
AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, "", 0)))
- .`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+ .`when`(appOpsController).getActiveAppOps(anyBoolean())
privacyItemController.addCallback(callback)
executor.runAllReady()
executor.runAllReady()
@@ -292,7 +292,7 @@
doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 0),
AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, "", 0)))
- .`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+ .`when`(appOpsController).getActiveAppOps(anyBoolean())
privacyItemController.addCallback(callback)
executor.runAllReady()
@@ -306,7 +306,7 @@
@Test
fun testNotUpdated_LocationChangeWhenOnlyMicCamera() {
doReturn(listOf(AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, "", 0)))
- .`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+ .`when`(appOpsController).getActiveAppOps(anyBoolean())
privacyItemController.addCallback(callback)
changeLocation(false)
@@ -338,7 +338,7 @@
fun testLogListUpdated() {
doReturn(listOf(
AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, 0))
- ).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+ ).`when`(appOpsController).getActiveAppOps(anyBoolean())
privacyItemController.addCallback(callback)
executor.runAllReady()
@@ -362,10 +362,10 @@
}
@Test
- fun testListRequestedForAllUsers() {
+ fun testListRequestedShowPaused() {
privacyItemController.addCallback(callback)
executor.runAllReady()
- verify(appOpsController).getActiveAppOpsForUser(UserHandle.USER_ALL)
+ verify(appOpsController).getActiveAppOps(true)
}
@Test
@@ -377,7 +377,7 @@
doReturn(listOf(
AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, 0),
AppOpItem(AppOpsManager.OP_CAMERA, otherUserUid, TEST_PACKAGE_NAME, 0))
- ).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+ ).`when`(appOpsController).getActiveAppOps(anyBoolean())
privacyItemController.userTrackerCallback.onUserChanged(otherUser, mContext)
executor.runAllReady()
@@ -401,7 +401,7 @@
AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, 0),
AppOpItem(AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, 0),
AppOpItem(AppOpsManager.OP_PHONE_CALL_CAMERA, TEST_UID, TEST_PACKAGE_NAME, 0))
- ).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+ ).`when`(appOpsController).getActiveAppOps(anyBoolean())
privacyItemController.userTrackerCallback.onUserChanged(otherUser, mContext)
executor.runAllReady()
@@ -424,7 +424,7 @@
AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, 0),
AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, 0),
AppOpItem(AppOpsManager.OP_PHONE_CALL_MICROPHONE, TEST_UID, TEST_PACKAGE_NAME, 0))
- ).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+ ).`when`(appOpsController).getActiveAppOps(anyBoolean())
privacyItemController.userTrackerCallback.onUserChanged(otherUser, mContext)
executor.runAllReady()
@@ -442,7 +442,7 @@
fun testPassageOfTimeDoesNotRemoveIndicators() {
doReturn(listOf(
AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, elapsedTime)
- )).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+ )).`when`(appOpsController).getActiveAppOps(anyBoolean())
privacyItemController.addCallback(callback)
@@ -458,12 +458,12 @@
// Start with some element at time 0
doReturn(listOf(
AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, elapsedTime)
- )).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+ )).`when`(appOpsController).getActiveAppOps(anyBoolean())
privacyItemController.addCallback(callback)
executor.runAllReady()
// Then remove it at time HOLD + 1
- doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+ doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOps(anyBoolean())
fakeClock.advanceTime(PrivacyItemController.TIME_TO_HOLD_INDICATORS + 1)
verify(appOpsController).addCallback(any(), capture(argCaptorCallback))
@@ -481,12 +481,12 @@
// Start with some element at time 0
doReturn(listOf(
AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, elapsedTime)
- )).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+ )).`when`(appOpsController).getActiveAppOps(anyBoolean())
privacyItemController.addCallback(callback)
executor.runAllReady()
// Then remove it at time HOLD - 1
- doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+ doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOps(anyBoolean())
fakeClock.advanceTime(PrivacyItemController.TIME_TO_HOLD_INDICATORS - 1)
verify(appOpsController).addCallback(any(), capture(argCaptorCallback))
@@ -504,12 +504,12 @@
// Start with some element at time 0
doReturn(listOf(
AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, elapsedTime)
- )).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+ )).`when`(appOpsController).getActiveAppOps(anyBoolean())
privacyItemController.addCallback(callback)
executor.runAllReady()
// Then remove it at time HOLD - 1
- doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+ doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOps(anyBoolean())
fakeClock.advanceTime(PrivacyItemController.TIME_TO_HOLD_INDICATORS - 1)
verify(appOpsController).addCallback(any(), capture(argCaptorCallback))
@@ -525,6 +525,30 @@
assertTrue(privacyItemController.privacyList.isEmpty())
}
+ @Test
+ fun testPausedElementsAreRemoved() {
+ val item = AppOpItem(
+ AppOpsManager.OP_RECORD_AUDIO,
+ TEST_UID,
+ TEST_PACKAGE_NAME,
+ elapsedTime
+ )
+ `when`(appOpsController.getActiveAppOps(anyBoolean())).thenReturn(listOf(item))
+ privacyItemController.addCallback(callback)
+ executor.runAllReady()
+
+ item.isDisabled = true
+ fakeClock.advanceTime(1)
+ verify(appOpsController).addCallback(any(), capture(argCaptorCallback))
+ argCaptorCallback.value.onActiveStateChanged(
+ AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, false)
+
+ executor.runAllReady()
+
+ verify(callback).onPrivacyItemsChanged(emptyList())
+ assertTrue(privacyItemController.privacyList.isEmpty())
+ }
+
private fun changeMicCamera(value: Boolean?) = changeProperty(MIC_CAMERA, value)
private fun changeLocation(value: Boolean?) = changeProperty(LOCATION_INDICATOR, value)
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 d236023..4bba0d0 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
@@ -233,6 +233,11 @@
}
@Test
+ public void testGetTileLabel() {
+ assertEquals(mContext.getString(R.string.wallet_title), mTile.getTileLabel().toString());
+ }
+
+ @Test
public void testHandleUpdateState_hasCard_deviceLocked_tileInactive() {
when(mKeyguardStateController.isUnlocked()).thenReturn(false);
QSTile.State state = new QSTile.State();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
index 67fd5eb..929a7e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
@@ -37,6 +37,8 @@
import com.android.systemui.R;
import com.android.systemui.SysuiBaseFragmentTest;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.events.PrivacyDotViewController;
+import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallListener;
@@ -58,6 +60,8 @@
private View mCenteredNotificationAreaView;
private StatusBarStateController mStatusBarStateController;
private OngoingCallController mOngoingCallController;
+ private SystemStatusAnimationScheduler mAnimationScheduler;
+ private PrivacyDotViewController mDotViewController;
public CollapsedStatusBarFragmentTest() {
super(CollapsedStatusBarFragment.class);
@@ -212,6 +216,11 @@
@Override
protected Fragment instantiate(Context context, String className, Bundle arguments) {
mOngoingCallController = mock(OngoingCallController.class);
- return new CollapsedStatusBarFragment(mOngoingCallController);
+ mAnimationScheduler = mock(SystemStatusAnimationScheduler.class);
+ mDotViewController = mock(PrivacyDotViewController.class);
+ return new CollapsedStatusBarFragment(
+ mOngoingCallController,
+ mAnimationScheduler,
+ mDotViewController);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 08d6d2d..11f96c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -38,6 +38,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.IWallpaperManager;
import android.app.Notification;
import android.app.StatusBarManager;
import android.app.trust.TrustManager;
@@ -113,6 +114,8 @@
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.charging.WiredChargingRippleController;
+import com.android.systemui.statusbar.events.PrivacyDotViewController;
+import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -263,8 +266,11 @@
@Mock private BrightnessSlider.Factory mBrightnessSliderFactory;
@Mock private WiredChargingRippleController mWiredChargingRippleController;
@Mock private OngoingCallController mOngoingCallController;
+ @Mock private SystemStatusAnimationScheduler mAnimationScheduler;
+ @Mock private PrivacyDotViewController mDotViewController;
@Mock private TunerService mTunerService;
@Mock private FeatureFlags mFeatureFlags;
+ @Mock private IWallpaperManager mWallpaperManager;
private ShadeController mShadeController;
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
private InitController mInitController = new InitController();
@@ -323,7 +329,8 @@
when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
- WakefulnessLifecycle wakefulnessLifecycle = new WakefulnessLifecycle();
+ WakefulnessLifecycle wakefulnessLifecycle =
+ new WakefulnessLifecycle(mContext, mWallpaperManager);
wakefulnessLifecycle.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
wakefulnessLifecycle.dispatchFinishedWakingUp();
@@ -429,6 +436,8 @@
mBrightnessSliderFactory,
mWiredChargingRippleController,
mOngoingCallController,
+ mAnimationScheduler,
+ mDotViewController,
mTunerService,
mFeatureFlags);
when(mKeyguardViewMediator.registerStatusBar(any(StatusBar.class), any(ViewGroup.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 4471778..40439a2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -36,7 +36,6 @@
import android.app.Instrumentation;
import android.net.ConnectivityManager;
-import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
@@ -323,34 +322,37 @@
public void setConnectivityViaCallbackInNetworkControllerForVcn(
int networkType, boolean validated, boolean isConnected, VcnTransportInfo info) {
- mNetCapabilities.setTransportInfo(info);
- setConnectivityCommon(networkType, validated, isConnected);
- mDefaultCallbackInNetworkController.onCapabilitiesChanged(
- mNetwork, new NetworkCapabilities(mNetCapabilities));
+ final NetworkCapabilities.Builder builder =
+ new NetworkCapabilities.Builder(mNetCapabilities);
+ builder.setTransportInfo(info);
+ setConnectivityCommon(builder, networkType, validated, isConnected);
+ mDefaultCallbackInNetworkController.onCapabilitiesChanged(mNetwork, builder.build());
}
public void setConnectivityViaCallbackInNetworkController(
int networkType, boolean validated, boolean isConnected, WifiInfo wifiInfo) {
+ final NetworkCapabilities.Builder builder =
+ new NetworkCapabilities.Builder(mNetCapabilities);
if (networkType == NetworkCapabilities.TRANSPORT_WIFI) {
- mNetCapabilities.setTransportInfo(wifiInfo);
+ builder.setTransportInfo(wifiInfo);
}
- setConnectivityCommon(networkType, validated, isConnected);
- mDefaultCallbackInNetworkController.onCapabilitiesChanged(
- mNetwork, new NetworkCapabilities(mNetCapabilities));
+ setConnectivityCommon(builder, networkType, validated, isConnected);
+ mDefaultCallbackInNetworkController.onCapabilitiesChanged(mNetwork, builder.build());
}
public void setConnectivityViaCallbackInWifiTracker(
int networkType, boolean validated, boolean isConnected, WifiInfo wifiInfo) {
+ final NetworkCapabilities.Builder builder =
+ new NetworkCapabilities.Builder(mNetCapabilities);
if (networkType == NetworkCapabilities.TRANSPORT_WIFI) {
- mNetCapabilities.setTransportInfo(wifiInfo);
+ builder.setTransportInfo(wifiInfo);
}
- setConnectivityCommon(networkType, validated, isConnected);
+ setConnectivityCommon(builder, networkType, validated, isConnected);
if (networkType == NetworkCapabilities.TRANSPORT_WIFI) {
if (isConnected) {
- mNetworkCallback.onAvailable(mNetwork,
- new NetworkCapabilities(mNetCapabilities), new LinkProperties(), false);
- mNetworkCallback.onCapabilitiesChanged(
- mNetwork, new NetworkCapabilities(mNetCapabilities));
+ final NetworkCapabilities newCap = builder.build();
+ mNetworkCallback.onAvailable(mNetwork);
+ mNetworkCallback.onCapabilitiesChanged(mNetwork, newCap);
} else {
mNetworkCallback.onLost(mNetwork);
}
@@ -359,16 +361,16 @@
public void setConnectivityViaCallbackInWifiTrackerForVcn(
int networkType, boolean validated, boolean isConnected, VcnTransportInfo info) {
- mNetCapabilities.setTransportInfo(info);
- setConnectivityCommon(networkType, validated, isConnected);
+ final NetworkCapabilities.Builder builder =
+ new NetworkCapabilities.Builder(mNetCapabilities);
+ builder.setTransportInfo(info);
+ setConnectivityCommon(builder, networkType, validated, isConnected);
if (networkType == NetworkCapabilities.TRANSPORT_CELLULAR) {
if (isConnected) {
- mNetworkCallback.onAvailable(mNetwork,
- new NetworkCapabilities(mNetCapabilities), new LinkProperties(), false);
- mNetworkCallback.onCapabilitiesChanged(
- mNetwork, new NetworkCapabilities(mNetCapabilities));
- mDefaultCallbackInWifiTracker.onCapabilitiesChanged(
- mNetwork, new NetworkCapabilities(mNetCapabilities));
+ final NetworkCapabilities newCap = builder.build();
+ mNetworkCallback.onAvailable(mNetwork);
+ mNetworkCallback.onCapabilitiesChanged(mNetwork, newCap);
+ mDefaultCallbackInWifiTracker.onCapabilitiesChanged(mNetwork, newCap);
} else {
mNetworkCallback.onLost(mNetwork);
}
@@ -377,26 +379,28 @@
public void setConnectivityViaDefaultCallbackInWifiTracker(
int networkType, boolean validated, boolean isConnected, WifiInfo wifiInfo) {
+ final NetworkCapabilities.Builder builder =
+ new NetworkCapabilities.Builder(mNetCapabilities);
if (networkType == NetworkCapabilities.TRANSPORT_WIFI) {
- mNetCapabilities.setTransportInfo(wifiInfo);
+ builder.setTransportInfo(wifiInfo);
}
- setConnectivityCommon(networkType, validated, isConnected);
+ setConnectivityCommon(builder, networkType, validated, isConnected);
mDefaultCallbackInWifiTracker.onCapabilitiesChanged(
- mNetwork, new NetworkCapabilities(mNetCapabilities));
+ mNetwork, builder.build());
}
- private void setConnectivityCommon(
+ private static void setConnectivityCommon(NetworkCapabilities.Builder builder,
int networkType, boolean validated, boolean isConnected){
// TODO: Separate out into several NetworkCapabilities.
if (isConnected) {
- mNetCapabilities.addTransportType(networkType);
+ builder.addTransportType(networkType);
} else {
- mNetCapabilities.removeTransportType(networkType);
+ builder.removeTransportType(networkType);
}
if (validated) {
- mNetCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
+ builder.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
} else {
- mNetCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
+ builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
index ed87a40..c38a547 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
@@ -202,8 +202,8 @@
@Test
public void testNetworkRequest() {
verify(mConnectivityManager, times(1)).registerNetworkCallback(argThat(
- (NetworkRequest request) -> request.networkCapabilities.getUids() == null
- && request.networkCapabilities.getCapabilities().length == 0
+ (NetworkRequest request) ->
+ request.equals(new NetworkRequest.Builder().clearCapabilities().build())
), any(NetworkCallback.class));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
index 653946e..6f6ef72 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
@@ -71,15 +71,17 @@
public class WalletScreenControllerTest extends SysuiTestCase {
private static final int MAX_CARDS = 10;
+ private static final int CARD_CAROUSEL_WIDTH = 10;
private static final String CARD_ID = "card_id";
private static final CharSequence SHORTCUT_SHORT_LABEL = "View all";
private static final CharSequence SHORTCUT_LONG_LABEL = "Add a payment method";
private static final CharSequence SERVICE_LABEL = "Wallet app";
- private final WalletView mWalletView = new WalletView(mContext);
private final Drawable mWalletLogo = mContext.getDrawable(android.R.drawable.ic_lock_lock);
private final Intent mWalletIntent = new Intent(QuickAccessWalletService.ACTION_VIEW_WALLET)
.setComponent(new ComponentName(mContext.getPackageName(), "WalletActivity"));
+ private WalletView mWalletView;
+
@Mock
QuickAccessWalletClient mWalletClient;
@Mock
@@ -104,6 +106,8 @@
MockitoAnnotations.initMocks(this);
mTestableLooper = TestableLooper.get(this);
when(mUserTracker.getUserContext()).thenReturn(mContext);
+ mWalletView = new WalletView(mContext);
+ mWalletView.getCardCarousel().setExpectedViewWidth(CARD_CAROUSEL_WIDTH);
when(mWalletClient.getLogo()).thenReturn(mWalletLogo);
when(mWalletClient.getShortcutLongLabel()).thenReturn(SHORTCUT_LONG_LABEL);
when(mWalletClient.getShortcutShortLabel()).thenReturn(SHORTCUT_SHORT_LABEL);
@@ -132,7 +136,12 @@
verify(mWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
- mCallbackCaptor.getValue().onWalletCardsRetrieved(response);
+ QuickAccessWalletClient.OnWalletCardsRetrievedCallback callback =
+ mCallbackCaptor.getValue();
+
+ assertEquals(mController, callback);
+
+ callback.onWalletCardsRetrieved(response);
mTestableLooper.processAllMessages();
assertEquals(VISIBLE, mWalletView.getCardCarouselContainer().getVisibility());
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 4d96162..16e6671 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -630,7 +630,9 @@
}
private static IDnsResolver getDnsResolver(Context context) {
- return IDnsResolver.Stub.asInterface(DnsResolverServiceManager.getService(context));
+ final DnsResolverServiceManager dsm = context.getSystemService(
+ DnsResolverServiceManager.class);
+ return IDnsResolver.Stub.asInterface(dsm.getService());
}
/** Handler thread used for all of the handlers below. */
@@ -1924,7 +1926,7 @@
newNc.setAdministratorUids(new int[0]);
if (!checkAnyPermissionOf(
callerPid, callerUid, android.Manifest.permission.NETWORK_FACTORY)) {
- newNc.setSubIds(Collections.emptySet());
+ newNc.setSubscriptionIds(Collections.emptySet());
}
return newNc;
@@ -3969,17 +3971,16 @@
// multilayer requests, returning as soon as a NetworkAgentInfo satisfies a request
// is important so as to not evaluate lower priority requests further in
// nri.mRequests.
- final boolean isNetworkNeeded = candidate.isSatisfyingRequest(req.requestId)
- // Note that this catches two important cases:
- // 1. Unvalidated cellular will not be reaped when unvalidated WiFi
- // is currently satisfying the request. This is desirable when
- // cellular ends up validating but WiFi does not.
- // 2. Unvalidated WiFi will not be reaped when validated cellular
- // is currently satisfying the request. This is desirable when
- // WiFi ends up validating and out scoring cellular.
- || nri.getSatisfier().getCurrentScore()
- < candidate.getCurrentScoreAsValidated();
- return isNetworkNeeded;
+ final NetworkAgentInfo champion = req.equals(nri.getActiveRequest())
+ ? nri.getSatisfier() : null;
+ // Note that this catches two important cases:
+ // 1. Unvalidated cellular will not be reaped when unvalidated WiFi
+ // is currently satisfying the request. This is desirable when
+ // cellular ends up validating but WiFi does not.
+ // 2. Unvalidated WiFi will not be reaped when validated cellular
+ // is currently satisfying the request. This is desirable when
+ // WiFi ends up validating and out scoring cellular.
+ return mNetworkRanker.mightBeat(req, champion, candidate.getValidatedScoreable());
}
}
@@ -5726,7 +5727,7 @@
}
mAppOpsManager.checkPackage(callerUid, callerPackageName);
- if (!nc.getSubIds().isEmpty()) {
+ if (!nc.getSubscriptionIds().isEmpty()) {
enforceNetworkFactoryPermission();
}
}
@@ -6148,6 +6149,7 @@
@Override
public int registerNetworkProvider(Messenger messenger, String name) {
enforceNetworkFactoryOrSettingsPermission();
+ Objects.requireNonNull(messenger, "messenger must be non-null");
NetworkProviderInfo npi = new NetworkProviderInfo(name, messenger,
nextNetworkProviderId(), () -> unregisterNetworkProvider(messenger));
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_PROVIDER, npi));
@@ -7811,7 +7813,7 @@
@NonNull final Collection<NetworkRequestInfo> networkRequests) {
final NetworkReassignment changes = new NetworkReassignment();
- // Gather the list of all relevant agents and sort them by score.
+ // Gather the list of all relevant agents.
final ArrayList<NetworkAgentInfo> nais = new ArrayList<>();
for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
if (!nai.everConnected) {
@@ -9186,6 +9188,7 @@
@Override
public void unregisterConnectivityDiagnosticsCallback(
@NonNull IConnectivityDiagnosticsCallback callback) {
+ Objects.requireNonNull(callback, "callback must be non-null");
mConnectivityDiagnosticsHandler.sendMessage(
mConnectivityDiagnosticsHandler.obtainMessage(
ConnectivityDiagnosticsHandler
@@ -9556,6 +9559,7 @@
*/
@Override
public void unregisterQosCallback(@NonNull final IQosCallback callback) {
+ Objects.requireNonNull(callback, "callback must be non-null");
mQosCallbackTracker.unregisterCallback(callback);
}
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 039f4d9..4b52057 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -729,7 +729,7 @@
// If multiple subscription IDs exist, they MUST all point to the same subscription
// group. Otherwise undefined behavior may occur.
- for (int subId : networkCapabilities.getSubIds()) {
+ for (int subId : networkCapabilities.getSubscriptionIds()) {
// Verify that all subscriptions point to the same group
if (subGrp != null && !subGrp.equals(snapshot.getGroupForSubId(subId))) {
Slog.wtf(TAG, "Got multiple subscription groups for a single network");
@@ -1003,14 +1003,14 @@
}
private boolean requiresRestartForCarrierWifi(NetworkCapabilities caps) {
- if (!caps.hasTransport(TRANSPORT_WIFI) || caps.getSubIds() == null) {
+ if (!caps.hasTransport(TRANSPORT_WIFI) || caps.getSubscriptionIds() == null) {
return false;
}
synchronized (mCaps) {
for (NetworkCapabilities existing : mCaps.values()) {
if (existing.hasTransport(TRANSPORT_WIFI)
- && caps.getSubIds().equals(existing.getSubIds())) {
+ && caps.getSubscriptionIds().equals(existing.getSubscriptionIds())) {
// Restart if any immutable capabilities have changed
return existing.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)
!= caps.hasCapability(NET_CAPABILITY_NOT_RESTRICTED);
diff --git a/services/core/java/com/android/server/connectivity/FullScore.java b/services/core/java/com/android/server/connectivity/FullScore.java
index 52da566..14cec09 100644
--- a/services/core/java/com/android/server/connectivity/FullScore.java
+++ b/services/core/java/com/android/server/connectivity/FullScore.java
@@ -259,6 +259,14 @@
}
/**
+ * Returns this score but validated.
+ */
+ public FullScore asValidated() {
+ return new FullScore(mLegacyInt, mPolicies | (1L << POLICY_IS_VALIDATED),
+ mKeepConnectedReason);
+ }
+
+ /**
* For backward compatibility, get the legacy int.
* This will be removed before S is published.
*/
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 584174e..18becd4 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -950,6 +950,26 @@
}
/**
+ * Returns a Scoreable identical to this NAI, but validated.
+ *
+ * This is useful to probe what scoring would be if this network validated, to know
+ * whether to provisionally keep a network that may or may not validate.
+ *
+ * @return a Scoreable identical to this NAI, but validated.
+ */
+ public NetworkRanker.Scoreable getValidatedScoreable() {
+ return new NetworkRanker.Scoreable() {
+ @Override public FullScore getScore() {
+ return mScore.asValidated();
+ }
+
+ @Override public NetworkCapabilities getCapsNoCopy() {
+ return networkCapabilities;
+ }
+ };
+ }
+
+ /**
* Return a {@link NetworkStateSnapshot} for this network.
*/
@NonNull
diff --git a/services/core/java/com/android/server/connectivity/NetworkRanker.java b/services/core/java/com/android/server/connectivity/NetworkRanker.java
index 2b345e5..346af44 100644
--- a/services/core/java/com/android/server/connectivity/NetworkRanker.java
+++ b/services/core/java/com/android/server/connectivity/NetworkRanker.java
@@ -234,16 +234,17 @@
NetworkAgentInfo bestNetwork = null;
int bestScore = Integer.MIN_VALUE;
for (final NetworkAgentInfo nai : nais) {
- if (nai.getCurrentScore() > bestScore) {
+ final int naiScore = nai.getCurrentScore();
+ if (naiScore > bestScore) {
bestNetwork = nai;
- bestScore = nai.getCurrentScore();
+ bestScore = naiScore;
}
}
return bestNetwork;
}
/**
- * Returns whether an offer has a chance to beat a champion network for a request.
+ * Returns whether a {@link Scoreable} has a chance to beat a champion network for a request.
*
* Offers are sent by network providers when they think they might be able to make a network
* with the characteristics contained in the offer. If the offer has no chance to beat
@@ -257,15 +258,15 @@
*
* @param request The request to evaluate against.
* @param champion The currently best network for this request.
- * @param offer The offer.
+ * @param contestant The offer.
* @return Whether the offer stands a chance to beat the champion.
*/
public boolean mightBeat(@NonNull final NetworkRequest request,
@Nullable final NetworkAgentInfo champion,
- @NonNull final NetworkOffer offer) {
+ @NonNull final Scoreable contestant) {
// If this network can't even satisfy the request then it can't beat anything, not
// even an absence of network. It can't satisfy it anyway.
- if (!request.canBeSatisfiedBy(offer.caps)) return false;
+ if (!request.canBeSatisfiedBy(contestant.getCapsNoCopy())) return false;
// If there is no satisfying network, then this network can beat, because some network
// is always better than no network.
if (null == champion) return true;
@@ -274,25 +275,24 @@
// Otherwise rank them.
final ArrayList<Scoreable> candidates = new ArrayList<>();
candidates.add(champion);
- candidates.add(offer);
- return offer == getBestNetworkByPolicy(candidates, champion);
+ candidates.add(contestant);
+ return contestant == getBestNetworkByPolicy(candidates, champion);
} else {
- return mightBeatByLegacyInt(request, champion.getScore(), offer);
+ return mightBeatByLegacyInt(champion.getScore(), contestant);
}
}
/**
- * Returns whether an offer might beat a champion according to the legacy int.
+ * Returns whether a contestant might beat a champion according to the legacy int.
*/
- public boolean mightBeatByLegacyInt(@NonNull final NetworkRequest request,
- @Nullable final FullScore championScore,
- @NonNull final NetworkOffer offer) {
+ private boolean mightBeatByLegacyInt(@Nullable final FullScore championScore,
+ @NonNull final Scoreable contestant) {
final int offerIntScore;
- if (offer.caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
+ if (contestant.getCapsNoCopy().hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
// If the offer might have Internet access, then it might validate.
- offerIntScore = offer.score.getLegacyIntAsValidated();
+ offerIntScore = contestant.getScore().getLegacyIntAsValidated();
} else {
- offerIntScore = offer.score.getLegacyInt();
+ offerIntScore = contestant.getScore().getLegacyInt();
}
return championScore.getLegacyInt() < offerIntScore;
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 7994fcc..94a5099 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -3177,7 +3177,7 @@
@BinderThread
@Override
- public void reportPerceptible(IBinder windowToken, boolean perceptible) {
+ public void reportPerceptibleAsync(IBinder windowToken, boolean perceptible) {
Objects.requireNonNull(windowToken, "windowToken must not be null");
int uid = Binder.getCallingUid();
synchronized (mMethodMap) {
@@ -5992,9 +5992,8 @@
@BinderThread
@Override
- public void reportStartInput(IBinder startInputToken, IVoidResultCallback resultCallback) {
- CallbackUtils.onResult(resultCallback,
- () -> mImms.reportStartInput(mToken, startInputToken));
+ public void reportStartInputAsync(IBinder startInputToken) {
+ mImms.reportStartInput(mToken, startInputToken);
}
@BinderThread
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 6244743..885093d 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -1840,7 +1840,7 @@
@BinderThread
@Override
- public void reportPerceptible(IBinder windowClient, boolean perceptible) {
+ public void reportPerceptibleAsync(IBinder windowClient, boolean perceptible) {
reportNotSupported();
}
diff --git a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
index 045e06d0..2ffc62a 100644
--- a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
+++ b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
@@ -178,8 +178,9 @@
}
/** Logs that a provider has entered or exited stationary throttling. */
- public void logProviderStationaryThrottled(String provider, boolean throttled) {
- addLogEvent(EVENT_PROVIDER_STATIONARY_THROTTLED, provider, throttled);
+ public void logProviderStationaryThrottled(String provider, boolean throttled,
+ ProviderRequest request) {
+ addLogEvent(EVENT_PROVIDER_STATIONARY_THROTTLED, provider, throttled, request);
}
/** Logs that the location power save mode has changed. */
@@ -217,7 +218,7 @@
(Integer) args[1], (CallerIdentity) args[2]);
case EVENT_PROVIDER_STATIONARY_THROTTLED:
return new ProviderStationaryThrottledEvent(timeDelta, (String) args[0],
- (Boolean) args[1]);
+ (Boolean) args[1], (ProviderRequest) args[2]);
case EVENT_LOCATION_POWER_SAVE_MODE_CHANGE:
return new LocationPowerSaveModeEvent(timeDelta, (Integer) args[0]);
default:
@@ -355,17 +356,19 @@
private static final class ProviderStationaryThrottledEvent extends ProviderEvent {
private final boolean mStationaryThrottled;
+ private final ProviderRequest mRequest;
ProviderStationaryThrottledEvent(long timeDelta, String provider,
- boolean stationaryThrottled) {
+ boolean stationaryThrottled, ProviderRequest request) {
super(timeDelta, provider);
mStationaryThrottled = stationaryThrottled;
+ mRequest = request;
}
@Override
public String getLogString() {
return mProvider + " provider stationary/idle " + (mStationaryThrottled ? "throttled"
- : "unthrottled");
+ : "unthrottled") + ", request = " + mRequest;
}
}
diff --git a/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java b/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java
index ab7e526..22a675a 100644
--- a/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java
@@ -206,7 +206,7 @@
if (D) {
Log.d(TAG, mName + " provider stationary throttled");
}
- EVENT_LOG.logProviderStationaryThrottled(mName, true);
+ EVENT_LOG.logProviderStationaryThrottled(mName, true, mOutgoingRequest);
}
if (mDeliverLastLocationCallback != null) {
@@ -224,7 +224,7 @@
}
} else {
if (oldThrottlingIntervalMs != INTERVAL_DISABLED) {
- EVENT_LOG.logProviderStationaryThrottled(mName, false);
+ EVENT_LOG.logProviderStationaryThrottled(mName, false, mOutgoingRequest);
if (D) {
Log.d(TAG, mName + " provider stationary unthrottled");
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 59f00a2..6cded50 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -1261,7 +1261,8 @@
return getCredentialTypeInternal(userId) != CREDENTIAL_TYPE_NONE;
}
- private void setKeystorePassword(byte[] password, int userHandle) {
+ @VisibleForTesting /** Note: this method is overridden in unit tests */
+ void setKeystorePassword(byte[] password, int userHandle) {
AndroidKeyStoreMaintenance.onUserPasswordChanged(userHandle, password);
}
diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
index 48ccad33..8818023 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
@@ -154,14 +154,14 @@
* Builds the Route selection request
*
* <p>This request is guaranteed to select carrier-owned, non-VCN underlying networks by virtue
- * of a populated set of subIds as expressed in NetworkCapabilities#getSubIds(). Only carrier
- * owned networks may be selected, as the request specifies only subIds in the VCN's
+ * of a populated set of subIds as expressed in NetworkCapabilities#getSubscriptionIds(). Only
+ * carrier owned networks may be selected, as the request specifies only subIds in the VCN's
* subscription group, while the VCN networks are excluded by virtue of not having subIds set on
* the VCN-exposed networks.
*/
private NetworkRequest getRouteSelectionRequest() {
return getBaseNetworkRequestBuilder()
- .setSubIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))
+ .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))
.build();
}
@@ -177,7 +177,7 @@
private NetworkRequest getWifiNetworkRequest() {
return getBaseNetworkRequestBuilder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .setSubIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))
+ .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))
.build();
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 89b7bbd..9acbdcc 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2378,6 +2378,46 @@
}
}
+ /**
+ * Propagate a wake event to the wallpaper engine.
+ */
+ public void notifyWakingUp(int x, int y, @NonNull Bundle extras) {
+ synchronized (mLock) {
+ final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
+ data.connection.forEachDisplayConnector(
+ displayConnector -> {
+ if (displayConnector.mEngine != null) {
+ try {
+ displayConnector.mEngine.dispatchWallpaperCommand(
+ WallpaperManager.COMMAND_WAKING_UP, x, y, -1, extras);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Propagate a sleep event to the wallpaper engine.
+ */
+ public void notifyGoingToSleep(int x, int y, @NonNull Bundle extras) {
+ synchronized (mLock) {
+ final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
+ data.connection.forEachDisplayConnector(
+ displayConnector -> {
+ if (displayConnector.mEngine != null) {
+ try {
+ displayConnector.mEngine.dispatchWallpaperCommand(
+ WallpaperManager.COMMAND_GOING_TO_SLEEP, x, y, -1, extras);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+ }
+
@Override
public boolean setLockWallpaperCallback(IWallpaperManagerCallback cb) {
checkPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW);
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index e4dc8c2..f021072 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -96,6 +96,8 @@
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
+import com.android.server.apphibernation.AppHibernationManagerInternal;
+import com.android.server.apphibernation.AppHibernationService;
import java.util.ArrayList;
import java.util.LinkedList;
@@ -163,6 +165,9 @@
*/
private final LaunchObserverRegistryImpl mLaunchObserver;
@VisibleForTesting static final int LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE = 512;
+ private final ArrayMap<String, Boolean> mLastHibernationStates = new ArrayMap<>();
+ private AppHibernationManagerInternal mAppHibernationManagerInternal;
+ private boolean mIsAppHibernationEnabled;
/**
* The information created when an intent is incoming but we do not yet know whether it will be
@@ -789,6 +794,27 @@
}
}
+ @Nullable
+ private AppHibernationManagerInternal getAppHibernationManagerInternal() {
+ if (mAppHibernationManagerInternal == null) {
+ mIsAppHibernationEnabled = AppHibernationService.isAppHibernationEnabled();
+ mAppHibernationManagerInternal =
+ LocalServices.getService(AppHibernationManagerInternal.class);
+ }
+ return mAppHibernationManagerInternal;
+ }
+
+ /**
+ * Notifies the tracker before the package is unstopped because of launching activity.
+ * @param packageName The package to be unstopped.
+ */
+ void notifyBeforePackageUnstopped(@NonNull String packageName) {
+ final AppHibernationManagerInternal ahmInternal = getAppHibernationManagerInternal();
+ if (ahmInternal != null && mIsAppHibernationEnabled) {
+ mLastHibernationStates.put(packageName, ahmInternal.isHibernatingGlobally(packageName));
+ }
+ }
+
/**
* Notifies the tracker that we called immediately before we call bindApplication on the client.
*
@@ -823,6 +849,8 @@
}
stopLaunchTrace(info);
+ final Boolean isHibernating =
+ mLastHibernationStates.remove(info.mLastLaunchedActivity.packageName);
if (abort) {
mSupervisor.stopWaitingForActivityVisible(info.mLastLaunchedActivity);
launchObserverNotifyActivityLaunchCancelled(info);
@@ -830,7 +858,7 @@
if (info.isInterestingToLoggerAndObserver()) {
launchObserverNotifyActivityLaunchFinished(info, timestampNs);
}
- logAppTransitionFinished(info);
+ logAppTransitionFinished(info, isHibernating != null ? isHibernating : false);
}
info.mPendingDrawActivities.clear();
mTransitionInfoList.remove(info);
@@ -859,7 +887,7 @@
}
}
- private void logAppTransitionFinished(@NonNull TransitionInfo info) {
+ private void logAppTransitionFinished(@NonNull TransitionInfo info, boolean isHibernating) {
if (DEBUG_METRICS) Slog.i(TAG, "logging finished transition " + info);
// Take a snapshot of the transition info before sending it to the handler for logging.
@@ -868,7 +896,7 @@
if (info.isInterestingToLoggerAndObserver()) {
BackgroundThread.getHandler().post(() -> logAppTransition(
info.mCurrentTransitionDeviceUptime, info.mCurrentTransitionDelayMs,
- infoSnapshot));
+ infoSnapshot, isHibernating));
}
BackgroundThread.getHandler().post(() -> logAppDisplayed(infoSnapshot));
if (info.mPendingFullyDrawn != null) {
@@ -880,7 +908,7 @@
// This gets called on a background thread without holding the activity manager lock.
private void logAppTransition(int currentTransitionDeviceUptime, int currentTransitionDelayMs,
- TransitionInfoSnapshot info) {
+ TransitionInfoSnapshot info, boolean isHibernating) {
final LogMaker builder = new LogMaker(APP_TRANSITION);
builder.setPackageName(info.packageName);
builder.setType(info.type);
@@ -933,7 +961,8 @@
packageOptimizationInfo.getCompilationReason(),
packageOptimizationInfo.getCompilationFilter(),
info.sourceType,
- info.sourceEventDelayMs);
+ info.sourceEventDelayMs,
+ isHibernating);
if (DEBUG_METRICS) {
Slog.i(TAG, String.format("APP_START_OCCURRED(%s, %s, %s, %s, %s)",
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 6d72999..aa9727a 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -189,6 +189,7 @@
import static com.android.server.wm.IdentifierProto.HASH_CODE;
import static com.android.server.wm.IdentifierProto.TITLE;
import static com.android.server.wm.IdentifierProto.USER_ID;
+import static com.android.server.wm.LetterboxConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
@@ -215,14 +216,8 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND;
-import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING;
-import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_SOLID_COLOR;
-import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_WALLPAPER;
-import static com.android.server.wm.WindowManagerService.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
-import static com.android.server.wm.WindowManagerService.letterboxBackgroundTypeToString;
import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY;
import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_BEFORE_ANIM;
@@ -268,7 +263,6 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
@@ -344,7 +338,6 @@
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.Task.ActivityState;
import com.android.server.wm.WindowManagerService.H;
-import com.android.server.wm.WindowManagerService.LetterboxBackgroundType;
import com.android.server.wm.utils.InsetUtils;
import com.google.android.collect.Sets;
@@ -587,10 +580,6 @@
AnimatingActivityRegistry mAnimatingActivityRegistry;
- // Set whenever the ActivityRecord gets reparented to a Task so we can know the last known
- // parent was when the ActivityRecord is detached from the hierarchy
- private Task mLastKnownParent;
-
// Set to the previous Task parent of the ActivityRecord when it is reparented to a new Task
// due to picture-in-picture. This gets cleared whenever this activity or the Task
// it references to gets removed. This should also be cleared when we move out of pip.
@@ -649,7 +638,8 @@
*/
private boolean mWillCloseOrEnterPip;
- private Letterbox mLetterbox;
+ @VisibleForTesting
+ final LetterboxUiController mLetterboxUiController;
/**
* The scale to fit at least one side of the activity to its parent. If the activity uses
@@ -678,8 +668,6 @@
@Nullable
private Rect mLetterboxBoundsForFixedOrientationAndAspectRatio;
- private boolean mShowWallpaperForLetterboxBackground;
-
// activity is not displayed?
// TODO: rename to mNoDisplay
@VisibleForTesting
@@ -1107,61 +1095,7 @@
pw.println(prefix + "lastParentTaskIdBeforePip=" + mLastParentBeforePip.mTaskId);
}
- dumpLetterboxInfo(pw, prefix);
- }
-
- private void dumpLetterboxInfo(PrintWriter pw, String prefix) {
- final WindowState mainWin = findMainWindow();
- if (mainWin == null) {
- return;
- }
-
- boolean areBoundsLetterboxed = mainWin.isLetterboxedAppWindow();
- pw.println(prefix + "areBoundsLetterboxed=" + areBoundsLetterboxed);
- if (!areBoundsLetterboxed) {
- return;
- }
-
- pw.println(prefix + " letterboxReason=" + getLetterboxReasonString(mainWin));
- pw.println(prefix + " letterboxAspectRatio=" + computeAspectRatio(getBounds()));
-
- boolean isLetterboxUiShown = isLetterboxed(mainWin);
- pw.println(prefix + "isLetterboxUiShown=" + isLetterboxUiShown);
-
- if (!isLetterboxUiShown) {
- return;
- }
- pw.println(prefix + " letterboxBackgroundColor=" + Integer.toHexString(
- getLetterboxBackgroundColor().toArgb()));
- pw.println(prefix + " letterboxBackgroundType="
- + letterboxBackgroundTypeToString(mWmService.getLetterboxBackgroundType()));
- if (mWmService.getLetterboxBackgroundType() == LETTERBOX_BACKGROUND_WALLPAPER) {
- pw.println(prefix + " isLetterboxWallpaperBlurSupported="
- + isLetterboxWallpaperBlurSupported());
- pw.println(prefix + " letterboxBackgroundWallpaperDarkScrimAlpha="
- + getLetterboxWallpaperDarkScrimAlpha());
- pw.println(prefix + " letterboxBackgroundWallpaperBlurRadius="
- + getLetterboxWallpaperBlurRadius());
- }
- pw.println(prefix + " letterboxHorizontalPositionMultiplier="
- + mWmService.getLetterboxHorizontalPositionMultiplier());
- }
-
- /**
- * Returns a string representing the reason for letterboxing. This method assumes the activity
- * is letterboxed.
- */
- private String getLetterboxReasonString(WindowState mainWin) {
- if (inSizeCompatMode()) {
- return "SIZE_COMPAT_MODE";
- }
- if (isLetterboxedForFixedOrientationAndAspectRatio()) {
- return "FIXED_ORIENTATION";
- }
- if (mainWin.isLetterboxedForDisplayCutout()) {
- return "DISPLAY_CUTOUT";
- }
- return "UNKNOWN_REASON";
+ mLetterboxUiController.dump(pw, prefix);
}
void setAppTimeTracker(AppTimeTracker att) {
@@ -1361,7 +1295,7 @@
if (getDisplayContent() != null) {
getDisplayContent().mClosingApps.remove(this);
}
- } else if (mLastKnownParent != null && mLastKnownParent.getRootTask() != null) {
+ } else if (oldTask != null && oldTask.getRootTask() != null) {
task.getRootTask().mExitingActivities.remove(this);
}
final Task rootTask = getRootTask();
@@ -1374,8 +1308,7 @@
? rootTask.getAnimatingActivityRegistry()
: null;
- mLastKnownParent = task;
- if (mLastKnownParent == mLastParentBeforePip) {
+ if (task == mLastParentBeforePip) {
// Activity's reparented back from pip, clear the links once established
clearLastParentBeforePip();
}
@@ -1451,183 +1384,29 @@
}
}
- if (mLetterbox != null) {
- mLetterbox.onMovedToDisplay(mDisplayContent.getDisplayId());
- }
+ mLetterboxUiController.onMovedToDisplay(mDisplayContent.getDisplayId());
}
- // TODO(b/183754168): Move letterbox UI logic into a separate class.
void layoutLetterbox(WindowState winHint) {
- final WindowState w = findMainWindow();
- if (w == null || winHint != null && w != winHint) {
- return;
- }
- final boolean surfaceReady = w.isDrawn() // Regular case
- || w.isDragResizeChanged(); // Waiting for relayoutWindow to call preserveSurface.
- final boolean needsLetterbox = surfaceReady && isLetterboxed(w);
- updateRoundedCorners(w);
- updateWallpaperForLetterbox(w);
- if (needsLetterbox) {
- if (mLetterbox == null) {
- mLetterbox = new Letterbox(() -> makeChildSurface(null),
- mWmService.mTransactionFactory,
- mWmService::isLetterboxActivityCornersRounded,
- this::getLetterboxBackgroundColor,
- this::hasWallpaperBackgroudForLetterbox,
- this::getLetterboxWallpaperBlurRadius,
- this::getLetterboxWallpaperDarkScrimAlpha);
- mLetterbox.attachInput(w);
- }
- getPosition(mTmpPoint);
- // Get the bounds of the "space-to-fill". The transformed bounds have the highest
- // priority because the activity is launched in a rotated environment. In multi-window
- // mode, the task-level represents this. In fullscreen-mode, the task container does
- // (since the orientation letterbox is also applied to the task).
- final Rect transformedBounds = getFixedRotationTransformDisplayBounds();
- final Rect spaceToFill = transformedBounds != null
- ? transformedBounds
- : inMultiWindowMode()
- ? getRootTask().getBounds()
- : getRootTask().getParent().getBounds();
- mLetterbox.layout(spaceToFill, w.getFrame(), mTmpPoint);
- } else if (mLetterbox != null) {
- mLetterbox.hide();
- }
- }
-
- private Color getLetterboxBackgroundColor() {
- final WindowState w = findMainWindow();
- if (w == null || w.isLetterboxedForDisplayCutout()) {
- return Color.valueOf(Color.BLACK);
- }
- @LetterboxBackgroundType int letterboxBackgroundType =
- mWmService.getLetterboxBackgroundType();
- switch (letterboxBackgroundType) {
- case LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING:
- if (taskDescription != null && taskDescription.getBackgroundColorFloating() != 0) {
- return Color.valueOf(taskDescription.getBackgroundColorFloating());
- }
- break;
- case LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND:
- if (taskDescription != null && taskDescription.getBackgroundColor() != 0) {
- return Color.valueOf(taskDescription.getBackgroundColor());
- }
- break;
- case LETTERBOX_BACKGROUND_WALLPAPER:
- if (hasWallpaperBackgroudForLetterbox()) {
- // Color is used for translucent scrim that dims wallpaper.
- return Color.valueOf(Color.BLACK);
- }
- Slog.w(TAG, "Wallpaper option is selected for letterbox background but "
- + "blur is not supported by a device or not supported in the current "
- + "window configuration or both alpha scrim and blur radius aren't "
- + "provided so using solid color background");
- break;
- case LETTERBOX_BACKGROUND_SOLID_COLOR:
- return mWmService.getLetterboxBackgroundColor();
- default:
- throw new AssertionError(
- "Unexpected letterbox background type: " + letterboxBackgroundType);
- }
- // If picked option configured incorrectly or not supported then default to a solid color
- // background.
- return mWmService.getLetterboxBackgroundColor();
- }
-
- /**
- * @return {@code true} when the main window is letterboxed, this activity isn't transparent
- * and doesn't show a wallpaper.
- */
- @VisibleForTesting
- boolean isLetterboxed(WindowState mainWindow) {
- return mainWindow.isLetterboxedAppWindow() && fillsParent()
- // Check for FLAG_SHOW_WALLPAPER explicitly instead of using
- // WindowContainer#showWallpaper because the later will return true when this
- // activity is using blurred wallpaper for letterbox backgroud.
- && (mainWindow.mAttrs.flags & FLAG_SHOW_WALLPAPER) == 0;
- }
-
- private void updateRoundedCorners(WindowState mainWindow) {
- int cornersRadius =
- // Don't round corners if letterboxed only for display cutout.
- isLetterboxed(mainWindow) && !mainWindow.isLetterboxedForDisplayCutout()
- ? Math.max(0, mWmService.getLetterboxActivityCornersRadius()) : 0;
- setCornersRadius(mainWindow, cornersRadius);
- }
-
- private void setCornersRadius(WindowState mainWindow, int cornersRadius) {
- final SurfaceControl windowSurface = mainWindow.getClientViewRootSurface();
- if (windowSurface != null && windowSurface.isValid()) {
- Transaction transaction = getSyncTransaction();
- transaction.setCornerRadius(windowSurface, cornersRadius);
- }
+ mLetterboxUiController.layoutLetterbox(winHint);
}
boolean hasWallpaperBackgroudForLetterbox() {
- return mShowWallpaperForLetterboxBackground;
- }
-
- private void updateWallpaperForLetterbox(WindowState mainWindow) {
- @LetterboxBackgroundType int letterboxBackgroundType =
- mWmService.getLetterboxBackgroundType();
- boolean wallpaperShouldBeShown =
- letterboxBackgroundType == LETTERBOX_BACKGROUND_WALLPAPER
- && isLetterboxed(mainWindow)
- // Don't use wallpaper as a background if letterboxed for display cutout.
- && !mainWindow.isLetterboxedForDisplayCutout()
- // Check that dark scrim alpha or blur radius are provided
- && (getLetterboxWallpaperBlurRadius() > 0
- || getLetterboxWallpaperDarkScrimAlpha() > 0)
- // Check that blur is supported by a device if blur radius is provided.
- && (getLetterboxWallpaperBlurRadius() <= 0
- || isLetterboxWallpaperBlurSupported());
- if (mShowWallpaperForLetterboxBackground != wallpaperShouldBeShown) {
- mShowWallpaperForLetterboxBackground = wallpaperShouldBeShown;
- requestUpdateWallpaperIfNeeded();
- }
- }
-
- private int getLetterboxWallpaperBlurRadius() {
- int blurRadius = mWmService.getLetterboxBackgroundWallpaperBlurRadius();
- return blurRadius < 0 ? 0 : blurRadius;
- }
-
- private float getLetterboxWallpaperDarkScrimAlpha() {
- float alpha = mWmService.getLetterboxBackgroundWallpaperDarkScrimAlpha();
- // No scrim by default.
- return (alpha < 0 || alpha >= 1) ? 0.0f : alpha;
- }
-
- private boolean isLetterboxWallpaperBlurSupported() {
- return mWmService.mContext.getSystemService(WindowManager.class).isCrossWindowBlurEnabled();
+ return mLetterboxUiController.hasWallpaperBackgroudForLetterbox();
}
void updateLetterboxSurface(WindowState winHint) {
- final WindowState w = findMainWindow();
- if (w != winHint && winHint != null && w != null) {
- return;
- }
- layoutLetterbox(winHint);
- if (mLetterbox != null && mLetterbox.needsApplySurfaceChanges()) {
- mLetterbox.applySurfaceChanges(getSyncTransaction());
- }
+ mLetterboxUiController.updateLetterboxSurface(winHint);
}
+ /** Gets the letterbox insets. The insets will be empty if there is no letterbox. */
Rect getLetterboxInsets() {
- if (mLetterbox != null) {
- return mLetterbox.getInsets();
- } else {
- return new Rect();
- }
+ return mLetterboxUiController.getLetterboxInsets();
}
/** Gets the inner bounds of letterbox. The bounds will be empty if there is no letterbox. */
void getLetterboxInnerBounds(Rect outBounds) {
- if (mLetterbox != null) {
- outBounds.set(mLetterbox.getInnerFrame());
- } else {
- outBounds.setEmpty();
- }
+ mLetterboxUiController.getLetterboxInnerBounds(outBounds);
}
/**
@@ -1635,7 +1414,7 @@
* when the current activity is displayed.
*/
boolean isFullyTransparentBarAllowed(Rect rect) {
- return mLetterbox == null || mLetterbox.notIntersectsOrFullyContains(rect);
+ return mLetterboxUiController.isFullyTransparentBarAllowed(rect);
}
/**
@@ -1643,7 +1422,7 @@
* the given {@code rect}.
*/
boolean isLetterboxOverlappingWith(Rect rect) {
- return mLetterbox != null && mLetterbox.isOverlappingWith(rect);
+ return mLetterboxUiController.isLetterboxOverlappingWith(rect);
}
static class Token extends IApplicationToken.Stub {
@@ -1892,6 +1671,9 @@
mPersistentState = persistentState;
taskDescription = _taskDescription;
+
+ mLetterboxUiController = new LetterboxUiController(mWmService, this);
+
if (_createTime > 0) {
createTime = _createTime;
}
@@ -2176,7 +1958,6 @@
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Add starting %s: startingData=%s",
this, startingData);
-
WindowManagerPolicy.StartingSurface surface = null;
try {
surface = startingData.createStartingSurface(ActivityRecord.this);
@@ -3724,10 +3505,8 @@
dc.setFocusedApp(null);
mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
}
- if (mLetterbox != null) {
- mLetterbox.destroy();
- mLetterbox = null;
- }
+
+ mLetterboxUiController.destroy();
if (!delayed) {
updateReportedVisibilityLocked();
@@ -7155,7 +6934,8 @@
offsetX = getHorizontalCenterOffset(
parentAppBounds.width(), screenResolvedBounds.width());
} else {
- float positionMultiplier = mWmService.getLetterboxHorizontalPositionMultiplier();
+ float positionMultiplier =
+ mWmService.mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier();
positionMultiplier =
(positionMultiplier < 0.0f || positionMultiplier > 1.0f)
// Default to central position if invalid value is provided.
@@ -7228,7 +7008,7 @@
// Override from config_fixedOrientationLetterboxAspectRatio or via ADB with
// set-fixed-orientation-letterbox-aspect-ratio.
final float letterboxAspectRatioOverride =
- mWmService.getFixedOrientationLetterboxAspectRatio();
+ mWmService.mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
aspect = letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
? letterboxAspectRatioOverride : aspect;
@@ -7746,7 +7526,7 @@
/**
* Returns the aspect ratio of the given {@code rect}.
*/
- private static float computeAspectRatio(Rect rect) {
+ static float computeAspectRatio(Rect rect) {
final int width = rect.width();
final int height = rect.height();
if (width == 0 || height == 0) {
diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
new file mode 100644
index 0000000..eb7087c
--- /dev/null
+++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
@@ -0,0 +1,328 @@
+/*
+ * 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.server.wm;
+
+import android.annotation.IntDef;
+import android.content.Context;
+import android.graphics.Color;
+
+import com.android.internal.R;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** Reads letterbox configs from resources and controls their overrides at runtime. */
+final class LetterboxConfiguration {
+
+ /**
+ * Override of aspect ratio for fixed orientation letterboxing that is set via ADB with
+ * set-fixed-orientation-letterbox-aspect-ratio or via {@link
+ * com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio} will be ignored
+ * if it is <= this value.
+ */
+ static final float MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO = 1.0f;
+
+ /** Enum for Letterbox background type. */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({LETTERBOX_BACKGROUND_SOLID_COLOR, LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND,
+ LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING, LETTERBOX_BACKGROUND_WALLPAPER})
+ @interface LetterboxBackgroundType {};
+ /** Solid background using color specified in R.color.config_letterboxBackgroundColor. */
+ static final int LETTERBOX_BACKGROUND_SOLID_COLOR = 0;
+
+ /** Color specified in R.attr.colorBackground for the letterboxed application. */
+ static final int LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND = 1;
+
+ /** Color specified in R.attr.colorBackgroundFloating for the letterboxed application. */
+ static final int LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING = 2;
+
+ /** Using wallpaper as a background which can be blurred or dimmed with dark scrim. */
+ static final int LETTERBOX_BACKGROUND_WALLPAPER = 3;
+
+ final Context mContext;
+
+ // Aspect ratio of letterbox for fixed orientation, values <=
+ // MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO will be ignored.
+ private float mFixedOrientationLetterboxAspectRatio;
+
+ // Corners radius for activities presented in the letterbox mode, values < 0 will be ignored.
+ private int mLetterboxActivityCornersRadius;
+
+ // Color for {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} letterbox background type.
+ private Color mLetterboxBackgroundColor;
+
+ @LetterboxBackgroundType
+ private int mLetterboxBackgroundType;
+
+ // Blur radius for LETTERBOX_BACKGROUND_WALLPAPER option in mLetterboxBackgroundType.
+ // Values <= 0 are ignored and 0 is used instead.
+ private int mLetterboxBackgroundWallpaperBlurRadius;
+
+ // Alpha of a black scrim shown over wallpaper letterbox background when
+ // LETTERBOX_BACKGROUND_WALLPAPER option is selected for mLetterboxBackgroundType.
+ // Values < 0 or >= 1 are ignored and 0.0 (transparent) is used instead.
+ private float mLetterboxBackgroundWallpaperDarkScrimAlpha;
+
+ // Horizontal position of a center of the letterboxed app window. 0 corresponds to the left
+ // side of the screen and 1.0 to the right side.
+ private float mLetterboxHorizontalPositionMultiplier;
+
+ LetterboxConfiguration(Context context) {
+ mContext = context;
+ mFixedOrientationLetterboxAspectRatio = context.getResources().getFloat(
+ R.dimen.config_fixedOrientationLetterboxAspectRatio);
+ mLetterboxActivityCornersRadius = context.getResources().getInteger(
+ R.integer.config_letterboxActivityCornersRadius);
+ mLetterboxBackgroundColor = Color.valueOf(context.getResources().getColor(
+ R.color.config_letterboxBackgroundColor));
+ mLetterboxBackgroundType = readLetterboxBackgroundTypeFromConfig(context);
+ mLetterboxBackgroundWallpaperBlurRadius = context.getResources().getDimensionPixelSize(
+ R.dimen.config_letterboxBackgroundWallpaperBlurRadius);
+ mLetterboxBackgroundWallpaperDarkScrimAlpha = context.getResources().getFloat(
+ R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha);
+ mLetterboxHorizontalPositionMultiplier = context.getResources().getFloat(
+ R.dimen.config_letterboxHorizontalPositionMultiplier);
+ }
+
+ /**
+ * Overrides the aspect ratio of letterbox for fixed orientation. If given value is <= {@link
+ * #MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO}, both it and a value of {@link
+ * com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio} will be ignored and
+ * the framework implementation will be used to determine the aspect ratio.
+ */
+ void setFixedOrientationLetterboxAspectRatio(float aspectRatio) {
+ mFixedOrientationLetterboxAspectRatio = aspectRatio;
+ }
+
+ /**
+ * Resets the aspect ratio of letterbox for fixed orientation to {@link
+ * com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio}.
+ */
+ void resetFixedOrientationLetterboxAspectRatio() {
+ mFixedOrientationLetterboxAspectRatio = mContext.getResources().getFloat(
+ com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio);
+ }
+
+ /**
+ * Gets the aspect ratio of letterbox for fixed orientation.
+ */
+ float getFixedOrientationLetterboxAspectRatio() {
+ return mFixedOrientationLetterboxAspectRatio;
+ }
+
+ /**
+ * Overrides corners raidus for activities presented in the letterbox mode. If given value < 0,
+ * both it and a value of {@link
+ * com.android.internal.R.integer.config_letterboxActivityCornersRadius} will be ignored and
+ * and corners of the activity won't be rounded.
+ */
+ void setLetterboxActivityCornersRadius(int cornersRadius) {
+ mLetterboxActivityCornersRadius = cornersRadius;
+ }
+
+ /**
+ * Resets corners raidus for activities presented in the letterbox mode to {@link
+ * com.android.internal.R.integer.config_letterboxActivityCornersRadius}.
+ */
+ void resetLetterboxActivityCornersRadius() {
+ mLetterboxActivityCornersRadius = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_letterboxActivityCornersRadius);
+ }
+
+ /**
+ * Whether corners of letterboxed activities are rounded.
+ */
+ boolean isLetterboxActivityCornersRounded() {
+ return getLetterboxActivityCornersRadius() > 0;
+ }
+
+ /**
+ * Gets corners raidus for activities presented in the letterbox mode.
+ */
+ int getLetterboxActivityCornersRadius() {
+ return mLetterboxActivityCornersRadius;
+ }
+
+ /**
+ * Gets color of letterbox background which is used when {@link
+ * #getLetterboxBackgroundType()} is {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} or as
+ * fallback for other backfround types.
+ */
+ Color getLetterboxBackgroundColor() {
+ return mLetterboxBackgroundColor;
+ }
+
+
+ /**
+ * Sets color of letterbox background which is used when {@link
+ * #getLetterboxBackgroundType()} is {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} or as
+ * fallback for other backfround types.
+ */
+ void setLetterboxBackgroundColor(Color color) {
+ mLetterboxBackgroundColor = color;
+ }
+
+ /**
+ * Resets color of letterbox background to {@link
+ * com.android.internal.R.color.config_letterboxBackgroundColor}.
+ */
+ void resetLetterboxBackgroundColor() {
+ mLetterboxBackgroundColor = Color.valueOf(mContext.getResources().getColor(
+ com.android.internal.R.color.config_letterboxBackgroundColor));
+ }
+
+ /**
+ * Gets {@link LetterboxBackgroundType} specified in {@link
+ * com.android.internal.R.integer.config_letterboxBackgroundType} or over via ADB command.
+ */
+ @LetterboxBackgroundType
+ int getLetterboxBackgroundType() {
+ return mLetterboxBackgroundType;
+ }
+
+ /** Sets letterbox background type. */
+ void setLetterboxBackgroundType(@LetterboxBackgroundType int backgroundType) {
+ mLetterboxBackgroundType = backgroundType;
+ }
+
+ /**
+ * Resets cletterbox background type to {@link
+ * com.android.internal.R.integer.config_letterboxBackgroundType}.
+ */
+ void resetLetterboxBackgroundType() {
+ mLetterboxBackgroundType = readLetterboxBackgroundTypeFromConfig(mContext);
+ }
+
+ /** Returns a string representing the given {@link LetterboxBackgroundType}. */
+ static String letterboxBackgroundTypeToString(
+ @LetterboxBackgroundType int backgroundType) {
+ switch (backgroundType) {
+ case LETTERBOX_BACKGROUND_SOLID_COLOR:
+ return "LETTERBOX_BACKGROUND_SOLID_COLOR";
+ case LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND:
+ return "LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND";
+ case LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING:
+ return "LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING";
+ case LETTERBOX_BACKGROUND_WALLPAPER:
+ return "LETTERBOX_BACKGROUND_WALLPAPER";
+ default:
+ return "unknown=" + backgroundType;
+ }
+ }
+
+ @LetterboxBackgroundType
+ private static int readLetterboxBackgroundTypeFromConfig(Context context) {
+ int backgroundType = context.getResources().getInteger(
+ com.android.internal.R.integer.config_letterboxBackgroundType);
+ return backgroundType == LETTERBOX_BACKGROUND_SOLID_COLOR
+ || backgroundType == LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND
+ || backgroundType == LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING
+ || backgroundType == LETTERBOX_BACKGROUND_WALLPAPER
+ ? backgroundType : LETTERBOX_BACKGROUND_SOLID_COLOR;
+ }
+
+ /**
+ * Overrides alpha of a black scrim shown over wallpaper for {@link
+ * #LETTERBOX_BACKGROUND_WALLPAPER} option in {@link mLetterboxBackgroundType}.
+ *
+ * <p>If given value is < 0 or >= 1, both it and a value of {@link
+ * com.android.internal.R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha} are ignored
+ * and 0.0 (transparent) is instead.
+ */
+ void setLetterboxBackgroundWallpaperDarkScrimAlpha(float alpha) {
+ mLetterboxBackgroundWallpaperDarkScrimAlpha = alpha;
+ }
+
+ /**
+ * Resets alpha of a black scrim shown over wallpaper letterbox background to {@link
+ * com.android.internal.R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha}.
+ */
+ void resetLetterboxBackgroundWallpaperDarkScrimAlpha() {
+ mLetterboxBackgroundWallpaperDarkScrimAlpha = mContext.getResources().getFloat(
+ com.android.internal.R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha);
+ }
+
+ /**
+ * Gets alpha of a black scrim shown over wallpaper letterbox background.
+ */
+ float getLetterboxBackgroundWallpaperDarkScrimAlpha() {
+ return mLetterboxBackgroundWallpaperDarkScrimAlpha;
+ }
+
+ /**
+ * Overrides blur radius for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option in
+ * {@link mLetterboxBackgroundType}.
+ *
+ * <p> If given value <= 0, both it and a value of {@link
+ * com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius} are ignored
+ * and 0 is used instead.
+ */
+ void setLetterboxBackgroundWallpaperBlurRadius(int radius) {
+ mLetterboxBackgroundWallpaperBlurRadius = radius;
+ }
+
+ /**
+ * Resets blur raidus for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option in {@link
+ * mLetterboxBackgroundType} to {@link
+ * com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius}.
+ */
+ void resetLetterboxBackgroundWallpaperBlurRadius() {
+ mLetterboxBackgroundWallpaperBlurRadius = mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius);
+ }
+
+ /**
+ * Gets blur raidus for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option in {@link
+ * mLetterboxBackgroundType}.
+ */
+ int getLetterboxBackgroundWallpaperBlurRadius() {
+ return mLetterboxBackgroundWallpaperBlurRadius;
+ }
+
+ /*
+ * Gets horizontal position of a center of the letterboxed app window specified
+ * in {@link com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier}
+ * or via an ADB command. 0 corresponds to the left side of the screen and 1 to the
+ * right side.
+ *
+ * <p>This value can be outside of [0, 1] range so clients need to check and default to the
+ * central position (0.5).
+ */
+ float getLetterboxHorizontalPositionMultiplier() {
+ return mLetterboxHorizontalPositionMultiplier;
+ }
+
+ /**
+ * Overrides horizontal position of a center of the letterboxed app window. If given value < 0
+ * or > 1, then it and a value of {@link
+ * com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier} are ignored and
+ * central position (0.5) is used.
+ */
+ void setLetterboxHorizontalPositionMultiplier(float multiplier) {
+ mLetterboxHorizontalPositionMultiplier = multiplier;
+ }
+
+ /**
+ * Resets horizontal position of a center of the letterboxed app window to {@link
+ * com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier}.
+ */
+ void resetLetterboxHorizontalPositionMultiplier() {
+ mLetterboxHorizontalPositionMultiplier = mContext.getResources().getFloat(
+ com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier);
+ }
+
+}
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
new file mode 100644
index 0000000..130f680
--- /dev/null
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -0,0 +1,336 @@
+/*
+ * 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.server.wm;
+
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_SOLID_COLOR;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_WALLPAPER;
+import static com.android.server.wm.LetterboxConfiguration.letterboxBackgroundTypeToString;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager.TaskDescription;
+import android.graphics.Color;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.util.Slog;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
+import android.view.WindowManager;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType;
+
+import java.io.PrintWriter;
+
+/** Controls behaviour of the letterbox UI for {@link mActivityRecord}. */
+// TODO(b/185262487): Improve test coverage of this class. Parts of it are tested in
+// SizeCompatTests and LetterboxTests but not all.
+// TODO(b/185264020): Consider making LetterboxUiController applicable to any level of the
+// hierarchy in addition to ActivityRecord (Task, DisplayArea, ...).
+final class LetterboxUiController {
+
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "LetterboxUiController" : TAG_ATM;
+
+ private final Point mTmpPoint = new Point();
+
+ private final LetterboxConfiguration mLetterboxConfiguration;
+ private final ActivityRecord mActivityRecord;
+
+ private boolean mShowWallpaperForLetterboxBackground;
+
+ @Nullable
+ private Letterbox mLetterbox;
+
+ LetterboxUiController(WindowManagerService wmService, ActivityRecord activityRecord) {
+ mLetterboxConfiguration = wmService.mLetterboxConfiguration;
+ // Given activityRecord may not be fully constructed since LetterboxUiController
+ // is created in its constructor. It shouldn't be used in this constructor but it's safe
+ // to use it after since controller is only used in ActivityRecord.
+ mActivityRecord = activityRecord;
+ }
+
+ /** Cleans up {@link Letterbox} if it exists.*/
+ void destroy() {
+ if (mLetterbox != null) {
+ mLetterbox.destroy();
+ mLetterbox = null;
+ }
+ }
+
+ void onMovedToDisplay(int displayId) {
+ if (mLetterbox != null) {
+ mLetterbox.onMovedToDisplay(displayId);
+ }
+ }
+
+ boolean hasWallpaperBackgroudForLetterbox() {
+ return mShowWallpaperForLetterboxBackground;
+ }
+
+ /** Gets the letterbox insets. The insets will be empty if there is no letterbox. */
+ Rect getLetterboxInsets() {
+ if (mLetterbox != null) {
+ return mLetterbox.getInsets();
+ } else {
+ return new Rect();
+ }
+ }
+
+ /** Gets the inner bounds of letterbox. The bounds will be empty if there is no letterbox. */
+ void getLetterboxInnerBounds(Rect outBounds) {
+ if (mLetterbox != null) {
+ outBounds.set(mLetterbox.getInnerFrame());
+ } else {
+ outBounds.setEmpty();
+ }
+ }
+
+ /**
+ * @return {@code true} if bar shown within a given rectangle is allowed to be fully transparent
+ * when the current activity is displayed.
+ */
+ boolean isFullyTransparentBarAllowed(Rect rect) {
+ return mLetterbox == null || mLetterbox.notIntersectsOrFullyContains(rect);
+ }
+
+ /**
+ * @return {@code true} if there is a letterbox and any part of that letterbox overlaps with
+ * the given {@code rect}.
+ */
+ boolean isLetterboxOverlappingWith(Rect rect) {
+ return mLetterbox != null && mLetterbox.isOverlappingWith(rect);
+ }
+
+ void updateLetterboxSurface(WindowState winHint) {
+ final WindowState w = mActivityRecord.findMainWindow();
+ if (w != winHint && winHint != null && w != null) {
+ return;
+ }
+ layoutLetterbox(winHint);
+ if (mLetterbox != null && mLetterbox.needsApplySurfaceChanges()) {
+ mLetterbox.applySurfaceChanges(mActivityRecord.getSyncTransaction());
+ }
+ }
+
+ void layoutLetterbox(WindowState winHint) {
+ final WindowState w = mActivityRecord.findMainWindow();
+ if (w == null || winHint != null && w != winHint) {
+ return;
+ }
+ final boolean surfaceReady = w.isDrawn() // Regular case
+ || w.isDragResizeChanged(); // Waiting for relayoutWindow to call preserveSurface.
+ final boolean needsLetterbox = surfaceReady && isLetterboxed(w);
+ updateRoundedCorners(w);
+ updateWallpaperForLetterbox(w);
+ if (needsLetterbox) {
+ if (mLetterbox == null) {
+ mLetterbox = new Letterbox(() -> mActivityRecord.makeChildSurface(null),
+ mActivityRecord.mWmService.mTransactionFactory,
+ mLetterboxConfiguration::isLetterboxActivityCornersRounded,
+ this::getLetterboxBackgroundColor,
+ this::hasWallpaperBackgroudForLetterbox,
+ this::getLetterboxWallpaperBlurRadius,
+ this::getLetterboxWallpaperDarkScrimAlpha);
+ mLetterbox.attachInput(w);
+ }
+ mActivityRecord.getPosition(mTmpPoint);
+ // Get the bounds of the "space-to-fill". The transformed bounds have the highest
+ // priority because the activity is launched in a rotated environment. In multi-window
+ // mode, the task-level represents this. In fullscreen-mode, the task container does
+ // (since the orientation letterbox is also applied to the task).
+ final Rect transformedBounds = mActivityRecord.getFixedRotationTransformDisplayBounds();
+ final Rect spaceToFill = transformedBounds != null
+ ? transformedBounds
+ : mActivityRecord.inMultiWindowMode()
+ ? mActivityRecord.getRootTask().getBounds()
+ : mActivityRecord.getRootTask().getParent().getBounds();
+ mLetterbox.layout(spaceToFill, w.getFrame(), mTmpPoint);
+ } else if (mLetterbox != null) {
+ mLetterbox.hide();
+ }
+ }
+
+ /**
+ * @return {@code true} when the main window is letterboxed, this activity isn't transparent
+ * and doesn't show a wallpaper.
+ */
+ @VisibleForTesting
+ boolean isLetterboxed(WindowState mainWindow) {
+ return mainWindow.isLetterboxedAppWindow() && mActivityRecord.fillsParent()
+ // Check for FLAG_SHOW_WALLPAPER explicitly instead of using
+ // WindowContainer#showWallpaper because the later will return true when this
+ // activity is using blurred wallpaper for letterbox backgroud.
+ && (mainWindow.mAttrs.flags & FLAG_SHOW_WALLPAPER) == 0;
+ }
+
+ private Color getLetterboxBackgroundColor() {
+ final WindowState w = mActivityRecord.findMainWindow();
+ if (w == null || w.isLetterboxedForDisplayCutout()) {
+ return Color.valueOf(Color.BLACK);
+ }
+ @LetterboxBackgroundType int letterboxBackgroundType =
+ mLetterboxConfiguration.getLetterboxBackgroundType();
+ TaskDescription taskDescription = mActivityRecord.taskDescription;
+ switch (letterboxBackgroundType) {
+ case LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING:
+ if (taskDescription != null && taskDescription.getBackgroundColorFloating() != 0) {
+ return Color.valueOf(taskDescription.getBackgroundColorFloating());
+ }
+ break;
+ case LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND:
+ if (taskDescription != null && taskDescription.getBackgroundColor() != 0) {
+ return Color.valueOf(taskDescription.getBackgroundColor());
+ }
+ break;
+ case LETTERBOX_BACKGROUND_WALLPAPER:
+ if (hasWallpaperBackgroudForLetterbox()) {
+ // Color is used for translucent scrim that dims wallpaper.
+ return Color.valueOf(Color.BLACK);
+ }
+ Slog.w(TAG, "Wallpaper option is selected for letterbox background but "
+ + "blur is not supported by a device or not supported in the current "
+ + "window configuration or both alpha scrim and blur radius aren't "
+ + "provided so using solid color background");
+ break;
+ case LETTERBOX_BACKGROUND_SOLID_COLOR:
+ return mLetterboxConfiguration.getLetterboxBackgroundColor();
+ default:
+ throw new AssertionError(
+ "Unexpected letterbox background type: " + letterboxBackgroundType);
+ }
+ // If picked option configured incorrectly or not supported then default to a solid color
+ // background.
+ return mLetterboxConfiguration.getLetterboxBackgroundColor();
+ }
+
+ private void updateRoundedCorners(WindowState mainWindow) {
+ int cornersRadius =
+ // Don't round corners if letterboxed only for display cutout.
+ isLetterboxed(mainWindow)
+ && !mainWindow.isLetterboxedForDisplayCutout()
+ ? Math.max(0, mLetterboxConfiguration.getLetterboxActivityCornersRadius())
+ : 0;
+ setCornersRadius(mainWindow, cornersRadius);
+ }
+
+ private void setCornersRadius(WindowState mainWindow, int cornersRadius) {
+ final SurfaceControl windowSurface = mainWindow.getClientViewRootSurface();
+ if (windowSurface != null && windowSurface.isValid()) {
+ Transaction transaction = mActivityRecord.getSyncTransaction();
+ transaction.setCornerRadius(windowSurface, cornersRadius);
+ }
+ }
+
+ private void updateWallpaperForLetterbox(WindowState mainWindow) {
+ @LetterboxBackgroundType int letterboxBackgroundType =
+ mLetterboxConfiguration.getLetterboxBackgroundType();
+ boolean wallpaperShouldBeShown =
+ letterboxBackgroundType == LETTERBOX_BACKGROUND_WALLPAPER
+ && isLetterboxed(mainWindow)
+ // Don't use wallpaper as a background if letterboxed for display cutout.
+ && !mainWindow.isLetterboxedForDisplayCutout()
+ // Check that dark scrim alpha or blur radius are provided
+ && (getLetterboxWallpaperBlurRadius() > 0
+ || getLetterboxWallpaperDarkScrimAlpha() > 0)
+ // Check that blur is supported by a device if blur radius is provided.
+ && (getLetterboxWallpaperBlurRadius() <= 0
+ || isLetterboxWallpaperBlurSupported());
+ if (mShowWallpaperForLetterboxBackground != wallpaperShouldBeShown) {
+ mShowWallpaperForLetterboxBackground = wallpaperShouldBeShown;
+ mActivityRecord.requestUpdateWallpaperIfNeeded();
+ }
+ }
+
+ private int getLetterboxWallpaperBlurRadius() {
+ int blurRadius = mLetterboxConfiguration.getLetterboxBackgroundWallpaperBlurRadius();
+ return blurRadius < 0 ? 0 : blurRadius;
+ }
+
+ private float getLetterboxWallpaperDarkScrimAlpha() {
+ float alpha = mLetterboxConfiguration.getLetterboxBackgroundWallpaperDarkScrimAlpha();
+ // No scrim by default.
+ return (alpha < 0 || alpha >= 1) ? 0.0f : alpha;
+ }
+
+ private boolean isLetterboxWallpaperBlurSupported() {
+ return mLetterboxConfiguration.mContext.getSystemService(WindowManager.class)
+ .isCrossWindowBlurEnabled();
+ }
+
+ void dump(PrintWriter pw, String prefix) {
+ final WindowState mainWin = mActivityRecord.findMainWindow();
+ if (mainWin == null) {
+ return;
+ }
+
+ boolean areBoundsLetterboxed = mainWin.isLetterboxedAppWindow();
+ pw.println(prefix + "areBoundsLetterboxed=" + areBoundsLetterboxed);
+ if (!areBoundsLetterboxed) {
+ return;
+ }
+
+ pw.println(prefix + " letterboxReason=" + getLetterboxReasonString(mainWin));
+ pw.println(prefix + " letterboxAspectRatio="
+ + mActivityRecord.computeAspectRatio(mActivityRecord.getBounds()));
+
+ boolean isLetterboxUiShown = isLetterboxed(mainWin);
+ pw.println(prefix + "isLetterboxUiShown=" + isLetterboxUiShown);
+
+ if (!isLetterboxUiShown) {
+ return;
+ }
+ pw.println(prefix + " letterboxBackgroundColor=" + Integer.toHexString(
+ getLetterboxBackgroundColor().toArgb()));
+ pw.println(prefix + " letterboxBackgroundType="
+ + letterboxBackgroundTypeToString(
+ mLetterboxConfiguration.getLetterboxBackgroundType()));
+ if (mLetterboxConfiguration.getLetterboxBackgroundType()
+ == LETTERBOX_BACKGROUND_WALLPAPER) {
+ pw.println(prefix + " isLetterboxWallpaperBlurSupported="
+ + isLetterboxWallpaperBlurSupported());
+ pw.println(prefix + " letterboxBackgroundWallpaperDarkScrimAlpha="
+ + getLetterboxWallpaperDarkScrimAlpha());
+ pw.println(prefix + " letterboxBackgroundWallpaperBlurRadius="
+ + getLetterboxWallpaperBlurRadius());
+ }
+ pw.println(prefix + " letterboxHorizontalPositionMultiplier="
+ + mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier());
+ }
+
+ /**
+ * Returns a string representing the reason for letterboxing. This method assumes the activity
+ * is letterboxed.
+ */
+ private String getLetterboxReasonString(WindowState mainWin) {
+ if (mActivityRecord.inSizeCompatMode()) {
+ return "SIZE_COMPAT_MODE";
+ }
+ if (mActivityRecord.isLetterboxedForFixedOrientationAndAspectRatio()) {
+ return "FIXED_ORIENTATION";
+ }
+ if (mainWin.isLetterboxedForDisplayCutout()) {
+ return "DISPLAY_CUTOUT";
+ }
+ return "UNKNOWN_REASON";
+ }
+
+}
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 95a4f69e..fb66c04 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -36,9 +36,11 @@
import android.animation.ArgbEvaluator;
import android.content.Context;
import android.graphics.Color;
+import android.graphics.GraphicBuffer;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
import android.os.Trace;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -210,9 +212,9 @@
String name = "RotationLayer";
mScreenshotLayer = displayContent.makeOverlay()
.setName(name)
- .setBufferSize(mWidth, mHeight)
.setSecure(isSecure)
.setCallsite("ScreenRotationAnimation")
+ .setBLASTLayer()
.build();
// This is the way to tell the input system to exclude this surface from occlusion
// detection since we don't have a window for it. We do this because this window is
@@ -225,32 +227,29 @@
.setCallsite("ScreenRotationAnimation")
.build();
- final Surface surface = mService.mSurfaceFactory.get();
- // In case display bounds change, screenshot buffer and surface may mismatch so
- // set a scaling mode.
- surface.copyFrom(mScreenshotLayer);
- surface.setScalingMode(Surface.SCALING_MODE_SCALE_TO_WINDOW);
-
+ HardwareBuffer hardwareBuffer = screenshotBuffer.getHardwareBuffer();
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
"ScreenRotationAnimation#getMedianBorderLuma");
- mStartLuma = RotationAnimationUtils.getMedianBorderLuma(
- screenshotBuffer.getHardwareBuffer(), screenshotBuffer.getColorSpace());
+ mStartLuma = RotationAnimationUtils.getMedianBorderLuma(hardwareBuffer,
+ screenshotBuffer.getColorSpace());
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- try {
- surface.attachAndQueueBufferWithColorSpace(screenshotBuffer.getHardwareBuffer(),
- screenshotBuffer.getColorSpace());
- } catch (RuntimeException e) {
- Slog.w(TAG, "Failed to attach screenshot - " + e.getMessage());
- }
+
+ GraphicBuffer buffer = GraphicBuffer.createFromHardwareBuffer(
+ screenshotBuffer.getHardwareBuffer());
+ // Scale the layer to the display size.
+ float dsdx = (float) mWidth / hardwareBuffer.getWidth();
+ float dsdy = (float) mHeight / hardwareBuffer.getHeight();
t.setLayer(mScreenshotLayer, SCREEN_FREEZE_LAYER_BASE);
t.reparent(mBackColorSurface, displayContent.getSurfaceControl());
t.setLayer(mBackColorSurface, -1);
t.setColor(mBackColorSurface, new float[]{mStartLuma, mStartLuma, mStartLuma});
t.setAlpha(mBackColorSurface, 1);
+ t.setBuffer(mScreenshotLayer, buffer);
+ t.setColorSpace(mScreenshotLayer, screenshotBuffer.getColorSpace());
+ t.setMatrix(mScreenshotLayer, dsdx, 0, 0, dsdy);
t.show(mScreenshotLayer);
t.show(mBackColorSurface);
- surface.destroy();
} catch (OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate freeze surface", e);
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index b82a308..c6cd560 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -640,9 +640,16 @@
}
}
- void windowAddedLocked(String packageName) {
- mPackageName = packageName;
- mRelayoutTag = "relayoutWindow: " + mPackageName;
+ void windowAddedLocked() {
+ if (mPackageName == null) {
+ final WindowProcessController wpc = mService.mAtmService.mProcessMap.getProcess(mPid);
+ if (wpc != null) {
+ mPackageName = wpc.mInfo.packageName;
+ mRelayoutTag = "relayoutWindow: " + mPackageName;
+ } else {
+ Slog.e(TAG_WM, "Unknown process pid=" + mPid);
+ }
+ }
if (mSurfaceSession == null) {
if (DEBUG) {
Slog.v(TAG_WM, "First window added to " + this + ", creating SurfaceSession");
diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java
index 140ae3e..603bfd1 100644
--- a/services/core/java/com/android/server/wm/StartingSurfaceController.java
+++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java
@@ -58,10 +58,12 @@
overrideConfig, displayId);
}
- final Task task = activity.getTask();
- if (task != null && mService.mAtmService.mTaskOrganizerController.addStartingWindow(task,
- activity.token, theme)) {
- return new ShellStartingSurface(task);
+ synchronized (mService.mGlobalLock) {
+ final Task task = activity.getTask();
+ if (task != null && mService.mAtmService.mTaskOrganizerController.addStartingWindow(
+ task, activity.token, theme)) {
+ return new ShellStartingSurface(task);
+ }
}
return null;
}
@@ -124,14 +126,13 @@
activity.mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(
topFullscreenActivity, false /* checkOpening */);
}
+ if (DEBUG_ENABLE_SHELL_DRAWER) {
+ mService.mAtmService.mTaskOrganizerController.addStartingWindow(task,
+ activity.token, 0 /* launchTheme */);
+ return new ShellStartingSurface(task);
+ }
}
- if (!DEBUG_ENABLE_SHELL_DRAWER) {
- return mService.mTaskSnapshotController
- .createStartingSurface(activity, taskSnapshot);
- }
- mService.mAtmService.mTaskOrganizerController.addStartingWindow(task, activity.token,
- 0 /* launchTheme */);
- return new ShellStartingSurface(task);
+ return mService.mTaskSnapshotController.createStartingSurface(activity, taskSnapshot);
}
@@ -144,8 +145,9 @@
@Override
public void remove(boolean animate) {
- mService.mAtmService.mTaskOrganizerController.removeStartingWindow(mTask,
- animate);
+ synchronized (mService.mGlobalLock) {
+ mService.mAtmService.mTaskOrganizerController.removeStartingWindow(mTask, animate);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/SurfaceFreezer.java b/services/core/java/com/android/server/wm/SurfaceFreezer.java
index 6f434e0..e0a791e 100644
--- a/services/core/java/com/android/server/wm/SurfaceFreezer.java
+++ b/services/core/java/com/android/server/wm/SurfaceFreezer.java
@@ -22,6 +22,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
@@ -153,29 +154,24 @@
*/
Snapshot(Supplier<Surface> surfaceFactory, SurfaceControl.Transaction t,
SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer, SurfaceControl parent) {
- Surface drawSurface = surfaceFactory.get();
// We can't use a delegating constructor since we need to
// reference this::onAnimationFinished
- HardwareBuffer hardwareBuffer = screenshotBuffer.getHardwareBuffer();
- final int width = hardwareBuffer.getWidth();
- final int height = hardwareBuffer.getHeight();
+ GraphicBuffer graphicBuffer = GraphicBuffer.createFromHardwareBuffer(
+ screenshotBuffer.getHardwareBuffer());
mSurfaceControl = mAnimatable.makeAnimationLeash()
.setName("snapshot anim: " + mAnimatable.toString())
- .setBufferSize(width, height)
.setFormat(PixelFormat.TRANSLUCENT)
.setParent(parent)
.setSecure(screenshotBuffer.containsSecureLayers())
.setCallsite("SurfaceFreezer.Snapshot")
+ .setBLASTLayer()
.build();
ProtoLog.i(WM_SHOW_TRANSACTIONS, " THUMBNAIL %s: CREATE", mSurfaceControl);
- // Transfer the thumbnail to the surface
- drawSurface.copyFrom(mSurfaceControl);
- drawSurface.attachAndQueueBufferWithColorSpace(hardwareBuffer,
- screenshotBuffer.getColorSpace());
- drawSurface.release();
+ t.setBuffer(mSurfaceControl, graphicBuffer);
+ t.setColorSpace(mSurfaceControl, screenshotBuffer.getColorSpace());
t.show(mSurfaceControl);
// We parent the thumbnail to the container, and just place it on top of anything else
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 07f81c7..858d9f3 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -6309,6 +6309,8 @@
// Launching this app's activity, make sure the app is no longer
// considered stopped.
try {
+ mTaskSupervisor.getActivityMetricsLogger()
+ .notifyBeforePackageUnstopped(next.packageName);
mAtmService.getPackageManager().setPackageStoppedState(
next.packageName, false, next.mUserId); /* TODO: Verify if correct userid */
} catch (RemoteException e1) {
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index dff621c..625cff3 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -439,6 +439,13 @@
taskDisplayArea = mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
}
+ // Re-route to default display if the home activity doesn't support multi-display
+ if (taskDisplayArea != null && activityRecord.isActivityTypeHome()
+ && !mSupervisor.mRootWindowContainer.canStartHomeOnDisplayArea(activityRecord.info,
+ taskDisplayArea, false /* allowInstrumenting */)) {
+ taskDisplayArea = mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
+ }
+
return (taskDisplayArea != null)
? taskDisplayArea
: getFallbackDisplayAreaForActivity(activityRecord, request);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0c9473a..d14a773 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -159,7 +159,6 @@
import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.Bitmap;
-import android.graphics.Color;
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Point;
@@ -977,56 +976,7 @@
private boolean mAnimationsDisabled = false;
boolean mPointerLocationEnabled = false;
- /**
- * Override of aspect ratio for fixed orientation letterboxing that is set via ADB with
- * set-fixed-orientation-letterbox-aspect-ratio or via {@link
- * com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio} will be ignored
- * if it is <= this value.
- */
- static final float MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO = 1.0f;
-
- /** Enum for Letterbox background type. */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({LETTERBOX_BACKGROUND_SOLID_COLOR, LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND,
- LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING, LETTERBOX_BACKGROUND_WALLPAPER})
- @interface LetterboxBackgroundType {};
- /** Solid background using color specified in R.color.config_letterboxBackgroundColor. */
- static final int LETTERBOX_BACKGROUND_SOLID_COLOR = 0;
-
- /** Color specified in R.attr.colorBackground for the letterboxed application. */
- static final int LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND = 1;
-
- /** Color specified in R.attr.colorBackgroundFloating for the letterboxed application. */
- static final int LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING = 2;
-
- /** Using wallpaper as a background which can be blurred or dimmed with dark scrim. */
- static final int LETTERBOX_BACKGROUND_WALLPAPER = 3;
-
- // Aspect ratio of letterbox for fixed orientation, values <=
- // MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO will be ignored.
- private float mFixedOrientationLetterboxAspectRatio;
-
- // Corners radius for activities presented in the letterbox mode, values < 0 will be ignored.
- private int mLetterboxActivityCornersRadius;
-
- // Color for {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} letterbox background type.
- private Color mLetterboxBackgroundColor;
-
- @LetterboxBackgroundType
- private int mLetterboxBackgroundType;
-
- // Blur radius for LETTERBOX_BACKGROUND_WALLPAPER option in mLetterboxBackgroundType.
- // Values <= 0 are ignored and 0 is used instead.
- private int mLetterboxBackgroundWallpaperBlurRadius;
-
- // Alpha of a black scrim shown over wallpaper letterbox background when
- // LETTERBOX_BACKGROUND_WALLPAPER option is selected for mLetterboxBackgroundType.
- // Values < 0 or >= 1 are ignored and 0.0 (transparent) is used instead.
- private float mLetterboxBackgroundWallpaperDarkScrimAlpha;
-
- // horizontal position of a center of the letterboxed app window. 0 corresponds to the left
- // side of the screen and 1.0 to the right side.
- private float mLetterboxHorizontalPositionMultiplier;
+ final LetterboxConfiguration mLetterboxConfiguration;
final InputManagerService mInputManager;
final DisplayManagerInternal mDisplayManagerInternal;
@@ -1258,19 +1208,7 @@
mAssistantOnTopOfDream = context.getResources().getBoolean(
com.android.internal.R.bool.config_assistantOnTopOfDream);
- mFixedOrientationLetterboxAspectRatio = context.getResources().getFloat(
- com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio);
- mLetterboxActivityCornersRadius = context.getResources().getInteger(
- com.android.internal.R.integer.config_letterboxActivityCornersRadius);
- mLetterboxBackgroundColor = Color.valueOf(context.getResources().getColor(
- com.android.internal.R.color.config_letterboxBackgroundColor));
- mLetterboxBackgroundType = readLetterboxBackgroundTypeFromConfig(context);
- mLetterboxBackgroundWallpaperBlurRadius = context.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius);
- mLetterboxBackgroundWallpaperDarkScrimAlpha = context.getResources().getFloat(
- com.android.internal.R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha);
- mLetterboxHorizontalPositionMultiplier = context.getResources().getFloat(
- com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier);
+ mLetterboxConfiguration = new LetterboxConfiguration(context);
mInputManager = inputManager; // Must be before createDisplayContentLocked.
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
@@ -3869,233 +3807,6 @@
}
}
- /**
- * Overrides the aspect ratio of letterbox for fixed orientation. If given value is <= {@link
- * #MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO}, both it and a value of {@link
- * com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio} will be ignored and
- * the framework implementation will be used to determine the aspect ratio.
- */
- void setFixedOrientationLetterboxAspectRatio(float aspectRatio) {
- mFixedOrientationLetterboxAspectRatio = aspectRatio;
- }
-
- /**
- * Resets the aspect ratio of letterbox for fixed orientation to {@link
- * com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio}.
- */
- void resetFixedOrientationLetterboxAspectRatio() {
- mFixedOrientationLetterboxAspectRatio = mContext.getResources().getFloat(
- com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio);
- }
-
- /**
- * Gets the aspect ratio of letterbox for fixed orientation.
- */
- float getFixedOrientationLetterboxAspectRatio() {
- return mFixedOrientationLetterboxAspectRatio;
- }
-
- /**
- * Overrides corners raidus for activities presented in the letterbox mode. If given value < 0,
- * both it and a value of {@link
- * com.android.internal.R.integer.config_letterboxActivityCornersRadius} will be ignored and
- * and corners of the activity won't be rounded.
- */
- void setLetterboxActivityCornersRadius(int cornersRadius) {
- mLetterboxActivityCornersRadius = cornersRadius;
- }
-
- /**
- * Resets corners raidus for activities presented in the letterbox mode to {@link
- * com.android.internal.R.integer.config_letterboxActivityCornersRadius}.
- */
- void resetLetterboxActivityCornersRadius() {
- mLetterboxActivityCornersRadius = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_letterboxActivityCornersRadius);
- }
-
- /**
- * Whether corners of letterboxed activities are rounded.
- */
- boolean isLetterboxActivityCornersRounded() {
- return getLetterboxActivityCornersRadius() > 0;
- }
-
- /**
- * Gets corners raidus for activities presented in the letterbox mode.
- */
- int getLetterboxActivityCornersRadius() {
- return mLetterboxActivityCornersRadius;
- }
-
- /**
- * Gets color of letterbox background which is used when {@link
- * #getLetterboxBackgroundType()} is {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} or as
- * fallback for other backfround types.
- */
- Color getLetterboxBackgroundColor() {
- return mLetterboxBackgroundColor;
- }
-
-
- /**
- * Sets color of letterbox background which is used when {@link
- * #getLetterboxBackgroundType()} is {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} or as
- * fallback for other backfround types.
- */
- void setLetterboxBackgroundColor(Color color) {
- mLetterboxBackgroundColor = color;
- }
-
- /**
- * Resets color of letterbox background to {@link
- * com.android.internal.R.color.config_letterboxBackgroundColor}.
- */
- void resetLetterboxBackgroundColor() {
- mLetterboxBackgroundColor = Color.valueOf(mContext.getResources().getColor(
- com.android.internal.R.color.config_letterboxBackgroundColor));
- }
-
- /**
- * Gets {@link LetterboxBackgroundType} specified in {@link
- * com.android.internal.R.integer.config_letterboxBackgroundType} or over via ADB command.
- */
- @LetterboxBackgroundType
- int getLetterboxBackgroundType() {
- return mLetterboxBackgroundType;
- }
-
- /** Sets letterbox background type. */
- void setLetterboxBackgroundType(@LetterboxBackgroundType int backgroundType) {
- mLetterboxBackgroundType = backgroundType;
- }
-
- /**
- * Resets cletterbox background type to {@link
- * com.android.internal.R.integer.config_letterboxBackgroundType}.
- */
- void resetLetterboxBackgroundType() {
- mLetterboxBackgroundType = readLetterboxBackgroundTypeFromConfig(mContext);
- }
-
- @LetterboxBackgroundType
- private static int readLetterboxBackgroundTypeFromConfig(Context context) {
- int backgroundType = context.getResources().getInteger(
- com.android.internal.R.integer.config_letterboxBackgroundType);
- return backgroundType == LETTERBOX_BACKGROUND_SOLID_COLOR
- || backgroundType == LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND
- || backgroundType == LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING
- || backgroundType == LETTERBOX_BACKGROUND_WALLPAPER
- ? backgroundType : LETTERBOX_BACKGROUND_SOLID_COLOR;
- }
-
- /** Returns a string representing the given {@link LetterboxBackgroundType}. */
- static String letterboxBackgroundTypeToString(
- @LetterboxBackgroundType int backgroundType) {
- switch (backgroundType) {
- case LETTERBOX_BACKGROUND_SOLID_COLOR:
- return "LETTERBOX_BACKGROUND_SOLID_COLOR";
- case LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND:
- return "LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND";
- case LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING:
- return "LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING";
- case LETTERBOX_BACKGROUND_WALLPAPER:
- return "LETTERBOX_BACKGROUND_WALLPAPER";
- default:
- return "unknown=" + backgroundType;
- }
- }
-
- /**
- * Overrides alpha of a black scrim shown over wallpaper for {@link
- * #LETTERBOX_BACKGROUND_WALLPAPER} option in {@link mLetterboxBackgroundType}.
- *
- * <p>If given value is < 0 or >= 1, both it and a value of {@link
- * com.android.internal.R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha} are ignored
- * and 0.0 (transparent) is instead.
- */
- void setLetterboxBackgroundWallpaperDarkScrimAlpha(float alpha) {
- mLetterboxBackgroundWallpaperDarkScrimAlpha = alpha;
- }
-
- /**
- * Resets alpha of a black scrim shown over wallpaper letterbox background to {@link
- * com.android.internal.R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha}.
- */
- void resetLetterboxBackgroundWallpaperDarkScrimAlpha() {
- mLetterboxBackgroundWallpaperDarkScrimAlpha = mContext.getResources().getFloat(
- com.android.internal.R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha);
- }
-
- /**
- * Gets alpha of a black scrim shown over wallpaper letterbox background.
- */
- float getLetterboxBackgroundWallpaperDarkScrimAlpha() {
- return mLetterboxBackgroundWallpaperDarkScrimAlpha;
- }
-
- /**
- * Overrides blur radius for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option in
- * {@link mLetterboxBackgroundType}.
- *
- * <p> If given value <= 0, both it and a value of {@link
- * com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius} are ignored
- * and 0 is used instead.
- */
- void setLetterboxBackgroundWallpaperBlurRadius(int radius) {
- mLetterboxBackgroundWallpaperBlurRadius = radius;
- }
-
- /**
- * Resets blur raidus for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option in {@link
- * mLetterboxBackgroundType} to {@link
- * com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius}.
- */
- void resetLetterboxBackgroundWallpaperBlurRadius() {
- mLetterboxBackgroundWallpaperBlurRadius = mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius);
- }
-
- /**
- * Gets blur raidus for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option in {@link
- * mLetterboxBackgroundType}.
- */
- int getLetterboxBackgroundWallpaperBlurRadius() {
- return mLetterboxBackgroundWallpaperBlurRadius;
- }
-
- /*
- * Gets horizontal position of a center of the letterboxed app window specified
- * in {@link com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier}
- * or via an ADB command. 0 corresponds to the left side of the screen and 1 to the
- * right side.
- *
- * <p>This value can be outside of [0, 1] range so clients need to check and default to the
- * central position (0.5).
- */
- float getLetterboxHorizontalPositionMultiplier() {
- return mLetterboxHorizontalPositionMultiplier;
- }
-
- /**
- * Overrides horizontal position of a center of the letterboxed app window. If given value < 0
- * or > 1, then it and a value of {@link
- * com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier} are ignored and
- * central position (0.5) is used.
- */
- void setLetterboxHorizontalPositionMultiplier(float multiplier) {
- mLetterboxHorizontalPositionMultiplier = multiplier;
- }
-
- /**
- * Resets horizontal position of a center of the letterboxed app window to {@link
- * com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier}.
- */
- void resetLetterboxHorizontalPositionMultiplier() {
- mLetterboxHorizontalPositionMultiplier = mContext.getResources().getFloat(
- com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier);
- }
-
@Override
public void setIgnoreOrientationRequest(int displayId, boolean ignoreOrientationRequest) {
if (!checkCallingPermission(
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 68257d4..1b578d1 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -19,10 +19,10 @@
import static android.os.Build.IS_USER;
import static android.view.CrossWindowBlurListeners.CROSS_WINDOW_BLUR_SUPPORTED;
-import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND;
-import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING;
-import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_SOLID_COLOR;
-import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_WALLPAPER;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_SOLID_COLOR;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_WALLPAPER;
import android.graphics.Color;
import android.graphics.Point;
@@ -41,7 +41,7 @@
import com.android.internal.protolog.ProtoLogImpl;
import com.android.server.LocalServices;
import com.android.server.statusbar.StatusBarManagerInternal;
-import com.android.server.wm.WindowManagerService.LetterboxBackgroundType;
+import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType;
import java.io.IOException;
import java.io.PrintWriter;
@@ -64,10 +64,12 @@
// Internal service impl -- must perform security checks before touching.
private final WindowManagerService mInternal;
+ private final LetterboxConfiguration mLetterboxConfiguration;
public WindowManagerShellCommand(WindowManagerService service) {
mInterface = service;
mInternal = service;
+ mLetterboxConfiguration = service.mLetterboxConfiguration;
}
@Override
@@ -119,34 +121,12 @@
return runGetIgnoreOrientationRequest(pw);
case "dump-visible-window-views":
return runDumpVisibleWindowViews(pw);
- case "set-fixed-orientation-letterbox-aspect-ratio":
- return runSetFixedOrientationLetterboxAspectRatio(pw);
- case "get-fixed-orientation-letterbox-aspect-ratio":
- return runGetFixedOrientationLetterboxAspectRatio(pw);
- case "set-letterbox-activity-corners-radius":
- return runSetLetterboxActivityCornersRadius(pw);
- case "get-letterbox-activity-corners-radius":
- return runGetLetterboxActivityCornersRadius(pw);
- case "set-letterbox-background-type":
- return runSetLetterboxBackgroundType(pw);
- case "get-letterbox-background-type":
- return runGetLetterboxBackgroundType(pw);
- case "set-letterbox-background-color":
- return runSetLetterboxBackgroundColor(pw);
- case "get-letterbox-background-color":
- return runGetLetterboxBackgroundColor(pw);
- case "set-letterbox-background-wallpaper-blur-radius":
- return runSetLetterboxBackgroundWallpaperBlurRadius(pw);
- case "get-letterbox-background-wallpaper-blur-radius":
- return runGetLetterboxBackgroundWallpaperBlurRadius(pw);
- case "set-letterbox-background-wallpaper-dark-scrim-alpha":
- return runSetLetterboxBackgroundWallpaperDarkScrimAlpha(pw);
- case "get-letterbox-background-wallpaper-dark-scrim-alpha":
- return runGetLetterboxBackgroundWallpaperDarkScrimAlpha(pw);
- case "set-letterbox-horizontal-position-multiplier":
- return runSeLetterboxHorizontalPositionMultiplier(pw);
- case "get-letterbox-horizontal-position-multiplier":
- return runGetLetterboxHorizontalPositionMultiplier(pw);
+ case "set-letterbox-style":
+ return runSetLetterboxStyle(pw);
+ case "get-letterbox-style":
+ return runGetLetterboxStyle(pw);
+ case "reset-letterbox-style":
+ return runResetLetterboxStyle(pw);
case "set-sandbox-display-apis":
return runSandboxDisplayApis(pw);
case "reset":
@@ -611,12 +591,6 @@
final float aspectRatio;
try {
String arg = getNextArgRequired();
- if ("reset".equals(arg)) {
- synchronized (mInternal.mGlobalLock) {
- mInternal.resetFixedOrientationLetterboxAspectRatio();
- }
- return 0;
- }
aspectRatio = Float.parseFloat(arg);
} catch (NumberFormatException e) {
getErrPrintWriter().println("Error: bad aspect ratio format " + e);
@@ -627,19 +601,7 @@
return -1;
}
synchronized (mInternal.mGlobalLock) {
- mInternal.setFixedOrientationLetterboxAspectRatio(aspectRatio);
- }
- return 0;
- }
-
- private int runGetFixedOrientationLetterboxAspectRatio(PrintWriter pw) throws RemoteException {
- synchronized (mInternal.mGlobalLock) {
- final float aspectRatio = mInternal.getFixedOrientationLetterboxAspectRatio();
- if (aspectRatio <= WindowManagerService.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO) {
- pw.println("Letterbox aspect ratio is not set");
- } else {
- pw.println("Letterbox aspect ratio is " + aspectRatio);
- }
+ mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(aspectRatio);
}
return 0;
}
@@ -648,12 +610,6 @@
final int cornersRadius;
try {
String arg = getNextArgRequired();
- if ("reset".equals(arg)) {
- synchronized (mInternal.mGlobalLock) {
- mInternal.resetLetterboxActivityCornersRadius();
- }
- return 0;
- }
cornersRadius = Integer.parseInt(arg);
} catch (NumberFormatException e) {
getErrPrintWriter().println("Error: bad corners radius format " + e);
@@ -664,110 +620,59 @@
return -1;
}
synchronized (mInternal.mGlobalLock) {
- mInternal.setLetterboxActivityCornersRadius(cornersRadius);
- }
- return 0;
- }
-
- private int runGetLetterboxActivityCornersRadius(PrintWriter pw) throws RemoteException {
- synchronized (mInternal.mGlobalLock) {
- final int cornersRadius = mInternal.getLetterboxActivityCornersRadius();
- if (cornersRadius < 0) {
- pw.println("Letterbox corners radius is not set");
- } else {
- pw.println("Letterbox corners radius is " + cornersRadius);
- }
+ mLetterboxConfiguration.setLetterboxActivityCornersRadius(cornersRadius);
}
return 0;
}
private int runSetLetterboxBackgroundType(PrintWriter pw) throws RemoteException {
@LetterboxBackgroundType final int backgroundType;
-
- String arg = getNextArgRequired();
- if ("reset".equals(arg)) {
- synchronized (mInternal.mGlobalLock) {
- mInternal.resetLetterboxBackgroundType();
- }
- return 0;
- }
- switch (arg) {
- case "solid_color":
- backgroundType = LETTERBOX_BACKGROUND_SOLID_COLOR;
- break;
- case "app_color_background":
- backgroundType = LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND;
- break;
- case "app_color_background_floating":
- backgroundType = LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING;
- break;
- case "wallpaper":
- backgroundType = LETTERBOX_BACKGROUND_WALLPAPER;
- break;
- default:
- getErrPrintWriter().println(
- "Error: 'reset', 'solid_color', 'app_color_background' or "
- + "'wallpaper' should be provided as an argument");
- return -1;
- }
- synchronized (mInternal.mGlobalLock) {
- mInternal.setLetterboxBackgroundType(backgroundType);
- }
- return 0;
- }
-
- private int runGetLetterboxBackgroundType(PrintWriter pw) throws RemoteException {
- synchronized (mInternal.mGlobalLock) {
- @LetterboxBackgroundType final int backgroundType =
- mInternal.getLetterboxBackgroundType();
- switch (backgroundType) {
- case LETTERBOX_BACKGROUND_SOLID_COLOR:
- pw.println("Letterbox background type is 'solid_color'");
+ try {
+ String arg = getNextArgRequired();
+ switch (arg) {
+ case "solid_color":
+ backgroundType = LETTERBOX_BACKGROUND_SOLID_COLOR;
break;
- case LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND:
- pw.println("Letterbox background type is 'app_color_background'");
+ case "app_color_background":
+ backgroundType = LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND;
break;
- case LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING:
- pw.println("Letterbox background type is 'app_color_background_floating'");
+ case "app_color_background_floating":
+ backgroundType = LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING;
break;
- case LETTERBOX_BACKGROUND_WALLPAPER:
- pw.println("Letterbox background type is 'wallpaper'");
+ case "wallpaper":
+ backgroundType = LETTERBOX_BACKGROUND_WALLPAPER;
break;
default:
- throw new AssertionError(
- "Unexpected letterbox background type: " + backgroundType);
+ getErrPrintWriter().println(
+ "Error: 'reset', 'solid_color', 'app_color_background' or "
+ + "'wallpaper' should be provided as an argument");
+ return -1;
}
+ } catch (IllegalArgumentException e) {
+ getErrPrintWriter().println(
+ "Error: 'reset', 'solid_color', 'app_color_background' or "
+ + "'wallpaper' should be provided as an argument" + e);
+ return -1;
+ }
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.setLetterboxBackgroundType(backgroundType);
}
return 0;
}
private int runSetLetterboxBackgroundColor(PrintWriter pw) throws RemoteException {
final Color color;
- String arg = getNextArgRequired();
try {
- if ("reset".equals(arg)) {
- synchronized (mInternal.mGlobalLock) {
- mInternal.resetLetterboxBackgroundColor();
- }
- return 0;
- }
+ String arg = getNextArgRequired();
color = Color.valueOf(Color.parseColor(arg));
} catch (IllegalArgumentException e) {
getErrPrintWriter().println(
"Error: 'reset' or color in #RRGGBB format should be provided as "
- + "an argument " + e + " but got " + arg);
+ + "an argument " + e);
return -1;
}
synchronized (mInternal.mGlobalLock) {
- mInternal.setLetterboxBackgroundColor(color);
- }
- return 0;
- }
-
- private int runGetLetterboxBackgroundColor(PrintWriter pw) throws RemoteException {
- synchronized (mInternal.mGlobalLock) {
- final Color color = mInternal.getLetterboxBackgroundColor();
- pw.println("Letterbox background color is " + Integer.toHexString(color.toArgb()));
+ mLetterboxConfiguration.setLetterboxBackgroundColor(color);
}
return 0;
}
@@ -777,12 +682,6 @@
final int radius;
try {
String arg = getNextArgRequired();
- if ("reset".equals(arg)) {
- synchronized (mInternal.mGlobalLock) {
- mInternal.resetLetterboxBackgroundWallpaperBlurRadius();
- }
- return 0;
- }
radius = Integer.parseInt(arg);
} catch (NumberFormatException e) {
getErrPrintWriter().println("Error: blur radius format " + e);
@@ -793,20 +692,7 @@
return -1;
}
synchronized (mInternal.mGlobalLock) {
- mInternal.setLetterboxBackgroundWallpaperBlurRadius(radius);
- }
- return 0;
- }
-
- private int runGetLetterboxBackgroundWallpaperBlurRadius(PrintWriter pw)
- throws RemoteException {
- synchronized (mInternal.mGlobalLock) {
- final int radius = mInternal.getLetterboxBackgroundWallpaperBlurRadius();
- if (radius <= 0) {
- pw.println("Letterbox background wallpaper blur radius is not set");
- } else {
- pw.println("Letterbox background wallpaper blur radius is " + radius);
- }
+ mLetterboxConfiguration.setLetterboxBackgroundWallpaperBlurRadius(radius);
}
return 0;
}
@@ -816,12 +702,6 @@
final float alpha;
try {
String arg = getNextArgRequired();
- if ("reset".equals(arg)) {
- synchronized (mInternal.mGlobalLock) {
- mInternal.resetLetterboxBackgroundWallpaperDarkScrimAlpha();
- }
- return 0;
- }
alpha = Float.parseFloat(arg);
} catch (NumberFormatException e) {
getErrPrintWriter().println("Error: bad alpha format " + e);
@@ -832,20 +712,7 @@
return -1;
}
synchronized (mInternal.mGlobalLock) {
- mInternal.setLetterboxBackgroundWallpaperDarkScrimAlpha(alpha);
- }
- return 0;
- }
-
- private int runGetLetterboxBackgroundWallpaperDarkScrimAlpha(PrintWriter pw)
- throws RemoteException {
- synchronized (mInternal.mGlobalLock) {
- final float alpha = mInternal.getLetterboxBackgroundWallpaperDarkScrimAlpha();
- if (alpha < 0 || alpha >= 1) {
- pw.println("Letterbox dark scrim alpha is not set");
- } else {
- pw.println("Letterbox dark scrim alpha is " + alpha);
- }
+ mLetterboxConfiguration.setLetterboxBackgroundWallpaperDarkScrimAlpha(alpha);
}
return 0;
}
@@ -854,12 +721,6 @@
final float multiplier;
try {
String arg = getNextArgRequired();
- if ("reset".equals(arg)) {
- synchronized (mInternal.mGlobalLock) {
- mInternal.resetLetterboxHorizontalPositionMultiplier();
- }
- return 0;
- }
multiplier = Float.parseFloat(arg);
} catch (NumberFormatException e) {
getErrPrintWriter().println("Error: bad multiplier format " + e);
@@ -870,23 +731,121 @@
return -1;
}
synchronized (mInternal.mGlobalLock) {
- mInternal.setLetterboxHorizontalPositionMultiplier(multiplier);
+ mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(multiplier);
}
return 0;
}
- private int runGetLetterboxHorizontalPositionMultiplier(PrintWriter pw) throws RemoteException {
- synchronized (mInternal.mGlobalLock) {
- final float multiplier = mInternal.getLetterboxHorizontalPositionMultiplier();
- if (multiplier < 0) {
- pw.println("Letterbox horizontal position multiplier is not set");
- } else {
- pw.println("Letterbox horizontal position multiplier is " + multiplier);
+ private int runSetLetterboxStyle(PrintWriter pw) throws RemoteException {
+ if (peekNextArg() == null) {
+ getErrPrintWriter().println("Error: No arguments provided.");
+ }
+ while (peekNextArg() != null) {
+ String arg = getNextArg();
+ switch (arg) {
+ case "--aspectRatio":
+ runSetFixedOrientationLetterboxAspectRatio(pw);
+ break;
+ case "--cornerRadius":
+ runSetLetterboxActivityCornersRadius(pw);
+ break;
+ case "--backgroundType":
+ runSetLetterboxBackgroundType(pw);
+ break;
+ case "--backgroundColor":
+ runSetLetterboxBackgroundColor(pw);
+ break;
+ case "--wallpaperBlurRadius":
+ runSetLetterboxBackgroundWallpaperBlurRadius(pw);
+ break;
+ case "--wallpaperDarkScrimAlpha":
+ runSetLetterboxBackgroundWallpaperDarkScrimAlpha(pw);
+ break;
+ case "--horizontalPositionMultiplier":
+ runSeLetterboxHorizontalPositionMultiplier(pw);
+ break;
+ default:
+ getErrPrintWriter().println(
+ "Error: Unrecognized letterbox style option: " + arg);
+ return -1;
}
}
return 0;
}
+ private int runResetLetterboxStyle(PrintWriter pw) throws RemoteException {
+ if (peekNextArg() == null) {
+ resetLetterboxStyle();
+ }
+ synchronized (mInternal.mGlobalLock) {
+ while (peekNextArg() != null) {
+ String arg = getNextArg();
+ switch (arg) {
+ case "aspectRatio":
+ mLetterboxConfiguration.resetFixedOrientationLetterboxAspectRatio();
+ break;
+ case "cornerRadius":
+ mLetterboxConfiguration.resetLetterboxActivityCornersRadius();
+ break;
+ case "backgroundType":
+ mLetterboxConfiguration.resetLetterboxBackgroundType();
+ break;
+ case "backgroundColor":
+ mLetterboxConfiguration.resetLetterboxBackgroundColor();
+ break;
+ case "wallpaperBlurRadius":
+ mLetterboxConfiguration.resetLetterboxBackgroundWallpaperBlurRadius();
+ break;
+ case "wallpaperDarkScrimAlpha":
+ mLetterboxConfiguration.resetLetterboxBackgroundWallpaperDarkScrimAlpha();
+ break;
+ case "horizontalPositionMultiplier":
+ mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier();
+ break;
+ default:
+ getErrPrintWriter().println(
+ "Error: Unrecognized letterbox style option: " + arg);
+ return -1;
+ }
+ }
+ }
+ return 0;
+ }
+
+ private void resetLetterboxStyle() {
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.resetFixedOrientationLetterboxAspectRatio();
+ mLetterboxConfiguration.resetLetterboxActivityCornersRadius();
+ mLetterboxConfiguration.resetLetterboxBackgroundType();
+ mLetterboxConfiguration.resetLetterboxBackgroundColor();
+ mLetterboxConfiguration.resetLetterboxBackgroundWallpaperBlurRadius();
+ mLetterboxConfiguration.resetLetterboxBackgroundWallpaperDarkScrimAlpha();
+ mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier();
+ }
+ }
+
+ private int runGetLetterboxStyle(PrintWriter pw) throws RemoteException {
+ synchronized (mInternal.mGlobalLock) {
+ pw.println("Corner radius: "
+ + mLetterboxConfiguration.getLetterboxActivityCornersRadius());
+ pw.println("Horizontal position multiplier: "
+ + mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier());
+ pw.println("Aspect ratio: "
+ + mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio());
+
+ pw.println("Background type: "
+ + LetterboxConfiguration.letterboxBackgroundTypeToString(
+ mLetterboxConfiguration.getLetterboxBackgroundType()));
+ pw.println(" Background color: " + Integer.toHexString(
+ mLetterboxConfiguration.getLetterboxBackgroundColor().toArgb()));
+ pw.println(" Wallpaper blur radius: "
+ + mLetterboxConfiguration.getLetterboxBackgroundWallpaperBlurRadius());
+ pw.println(" Wallpaper dark scrim alpha: "
+ + mLetterboxConfiguration.getLetterboxBackgroundWallpaperDarkScrimAlpha());
+ }
+ return 0;
+ }
+
private int runReset(PrintWriter pw) throws RemoteException {
int displayId = getDisplayId(getNextArg());
@@ -911,26 +870,8 @@
// set-ignore-orientation-request
mInterface.setIgnoreOrientationRequest(displayId, false /* ignoreOrientationRequest */);
- // set-fixed-orientation-letterbox-aspect-ratio
- mInternal.resetFixedOrientationLetterboxAspectRatio();
-
- // set-letterbox-activity-corners-radius
- mInternal.resetLetterboxActivityCornersRadius();
-
- // set-letterbox-background-type
- mInternal.resetLetterboxBackgroundType();
-
- // set-letterbox-background-color
- mInternal.resetLetterboxBackgroundColor();
-
- // set-letterbox-background-wallpaper-blur-radius
- mInternal.resetLetterboxBackgroundWallpaperBlurRadius();
-
- // set-letterbox-background-wallpaper-dark-scrim-alpha
- mInternal.resetLetterboxBackgroundWallpaperDarkScrimAlpha();
-
- // set-letterbox-horizontal-position-multiplier
- mInternal.resetLetterboxHorizontalPositionMultiplier();
+ // set-letterbox-style
+ resetLetterboxStyle();
// set-sandbox-display-apis
mInternal.setSandboxDisplayApis(displayId, /* sandboxDisplayApis= */ true);
@@ -966,47 +907,13 @@
pw.println(" set-ignore-orientation-request [-d DISPLAY_ID] [true|1|false|0]");
pw.println(" get-ignore-orientation-request [-d DISPLAY_ID] ");
pw.println(" If app requested orientation should be ignored.");
- pw.println(" set-fixed-orientation-letterbox-aspect-ratio [reset|aspectRatio]");
- pw.println(" get-fixed-orientation-letterbox-aspect-ratio");
- pw.println(" Aspect ratio of letterbox for fixed orientation. If aspectRatio <= "
- + WindowManagerService.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO);
- pw.println(" both it and R.dimen.config_fixedOrientationLetterboxAspectRatio will be");
- pw.println(" ignored and framework implementation will determine aspect ratio.");
- pw.println(" set-letterbox-activity-corners-radius [reset|cornersRadius]");
- pw.println(" get-letterbox-activity-corners-radius");
- pw.println(" Corners radius for activities in the letterbox mode. If radius < 0,");
- pw.println(" both it and R.integer.config_letterboxActivityCornersRadius will be");
- pw.println(" ignored and corners of the activity won't be rounded.");
- pw.println(" set-letterbox-background-color [reset|colorName|'\\#RRGGBB']");
- pw.println(" get-letterbox-background-color");
- pw.println(" Color of letterbox background which is be used when letterbox background");
- pw.println(" type is 'solid-color'. Use get(set)-letterbox-background-type to check");
- pw.println(" and control letterbox background type. See Color#parseColor for allowed");
- pw.println(" color formats (#RRGGBB and some colors by name, e.g. magenta or olive). ");
- pw.println(" set-letterbox-background-type [reset|solid_color|app_color_background");
- pw.println(" |app_color_background_floating|wallpaper]");
- pw.println(" get-letterbox-background-type");
- pw.println(" Type of background used in the letterbox mode.");
- pw.println(" set-letterbox-background-wallpaper-blur-radius [reset|radius]");
- pw.println(" get-letterbox-background-wallpaper-blur-radius");
- pw.println(" Blur radius for 'wallpaper' letterbox background. If radius <= 0");
- pw.println(" both it and R.dimen.config_letterboxBackgroundWallpaperBlurRadius are ");
- pw.println(" ignored and 0 is used.");
- pw.println(" set-letterbox-background-wallpaper-dark-scrim-alpha [reset|alpha]");
- pw.println(" get-letterbox-background-wallpaper-dark-scrim-alpha");
- pw.println(" Alpha of a black translucent scrim shown over 'wallpaper'");
- pw.println(" letterbox background. If alpha < 0 or >= 1 both it and");
- pw.println(" R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha are ignored and ");
- pw.println(" 0.0 (transparent) is used instead.");
- pw.println(" set-letterbox-horizontal-position-multiplier [reset|multiplier]");
- pw.println(" get-letterbox-horizontal-position-multiplier");
- pw.println(" horizontal position of a center of a letterboxed app. If it < 0 or > 1");
- pw.println(" then both it and R.dimen.config_letterboxHorizontalPositionMultiplier");
- pw.println(" are ignored and central position (0.5) is used.");
pw.println(" set-sandbox-display-apis [true|1|false|0]");
pw.println(" Sets override of Display APIs getRealSize / getRealMetrics to reflect ");
pw.println(" DisplayArea of the activity, or the window bounds if in letterbox or");
pw.println(" Size Compat Mode.");
+
+ printLetterboxHelp(pw);
+
pw.println(" reset [-d DISPLAY_ID]");
pw.println(" Reset all override settings.");
if (!IS_USER) {
@@ -1016,4 +923,47 @@
pw.println(" Logging settings.");
}
}
+
+ private void printLetterboxHelp(PrintWriter pw) {
+ pw.println(" set-letterbox-style");
+ pw.println(" Sets letterbox style using the following options:");
+ pw.println(" --aspectRatio aspectRatio");
+ pw.println(" Aspect ratio of letterbox for fixed orientation. If aspectRatio <= "
+ + LetterboxConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO);
+ pw.println(" both it and R.dimen.config_fixedOrientationLetterboxAspectRatio will");
+ pw.println(" be ignored and framework implementation will determine aspect ratio.");
+ pw.println(" --cornerRadius radius");
+ pw.println(" Corners radius for activities in the letterbox mode. If radius < 0,");
+ pw.println(" both it and R.integer.config_letterboxActivityCornersRadius will be");
+ pw.println(" ignored and corners of the activity won't be rounded.");
+ pw.println(" --backgroundType [reset|solid_color|app_color_background");
+ pw.println(" |app_color_background_floating|wallpaper]");
+ pw.println(" Type of background used in the letterbox mode.");
+ pw.println(" --backgroundColor color");
+ pw.println(" Color of letterbox which is be used when letterbox background type");
+ pw.println(" is 'solid-color'. Use (set)get-letterbox-style to check and control");
+ pw.println(" letterbox background type. See Color#parseColor for allowed color");
+ pw.println(" formats (#RRGGBB and some colors by name, e.g. magenta or olive).");
+ pw.println(" --wallpaperBlurRadius radius");
+ pw.println(" Blur radius for 'wallpaper' letterbox background. If radius <= 0");
+ pw.println(" both it and R.dimen.config_letterboxBackgroundWallpaperBlurRadius");
+ pw.println(" are ignored and 0 is used.");
+ pw.println(" --wallpaperDarkScrimAlpha alpha");
+ pw.println(" Alpha of a black translucent scrim shown over 'wallpaper'");
+ pw.println(" letterbox background. If alpha < 0 or >= 1 both it and");
+ pw.println(" R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha are ignored");
+ pw.println(" and 0.0 (transparent) is used instead.");
+ pw.println(" --horizontalPositionMultiplier multiplier");
+ pw.println(" Horizontal position of app window center. If multiplier < 0 or > 1,");
+ pw.println(" both it and R.dimen.config_letterboxHorizontalPositionMultiplier");
+ pw.println(" are ignored and central position (0.5) is used.");
+ pw.println(" reset-letterbox-style [aspectRatio|cornerRadius|backgroundType");
+ pw.println(" |backgroundColor|wallpaperBlurRadius|wallpaperDarkScrimAlpha");
+ pw.println(" |horizontalPositionMultiplier]");
+ pw.println(" Resets overrides to default values for specified properties separated");
+ pw.println(" by space, e.g. 'reset-letterbox-style aspectRatio cornerRadius'.");
+ pw.println(" If no arguments provided, all values will be reset.");
+ pw.println(" get-letterbox-style");
+ pw.println(" Prints letterbox style configuration.");
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 2e37fee..9382b8e 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -36,6 +36,7 @@
import android.app.WindowConfiguration;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Binder;
@@ -45,7 +46,6 @@
import android.os.RemoteException;
import android.util.ArraySet;
import android.util.Slog;
-import android.view.Surface;
import android.view.SurfaceControl;
import android.window.IDisplayAreaOrganizerController;
import android.window.ITaskOrganizerController;
@@ -766,18 +766,21 @@
return false;
}
+ GraphicBuffer graphicBuffer = GraphicBuffer.createFromHardwareBuffer(
+ buffer.getHardwareBuffer());
SurfaceControl screenshot = mService.mWindowManager.mSurfaceControlFactory.apply(null)
.setName(wc.getName() + " - Organizer Screenshot")
- .setBufferSize(bounds.width(), bounds.height())
.setFormat(PixelFormat.TRANSLUCENT)
.setParent(wc.getParentSurfaceControl())
+ .setSecure(buffer.containsSecureLayers())
.setCallsite("WindowOrganizerController.takeScreenshot")
+ .setBLASTLayer()
.build();
- Surface surface = new Surface();
- surface.copyFrom(screenshot);
- surface.attachAndQueueBufferWithColorSpace(buffer.getHardwareBuffer(), null);
- surface.release();
+ SurfaceControl.Transaction transaction = mService.mWindowManager.mTransactionFactory.get();
+ transaction.setBuffer(screenshot, graphicBuffer);
+ transaction.setColorSpace(screenshot, buffer.getColorSpace());
+ transaction.apply();
outSurfaceControl.copyFrom(screenshot, "WindowOrganizerController.takeScreenshot");
return true;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 46d923b..1a5042f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1140,7 +1140,7 @@
void attach() {
if (DEBUG) Slog.v(TAG, "Attaching " + this + " token=" + mToken);
- mSession.windowAddedLocked(mAttrs.packageName);
+ mSession.windowAddedLocked();
}
/**
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index cf9b88a..6283b4e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -96,6 +96,7 @@
import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_SETTING_PROFILE_OWNER_FAILED;
import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_SET_DEVICE_OWNER_FAILED;
import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_STARTING_PROFILE_FAILED;
+import static android.app.admin.DevicePolicyManager.STATE_USER_UNMANAGED;
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
@@ -8735,7 +8736,8 @@
final CallerIdentity caller = getCallerIdentity();
if (userHandle != mOwners.getDeviceOwnerUserId() && !mOwners.hasProfileOwner(userHandle)
- && getManagedUserId(userHandle) == -1) {
+ && getManagedUserId(userHandle) == -1
+ && newState != STATE_USER_UNMANAGED) {
// No managed device, user or profile, so setting provisioning state makes no sense.
throw new IllegalStateException("Not allowed to change provisioning state unless a "
+ "device or profile owner is set.");
@@ -8798,6 +8800,12 @@
case DevicePolicyManager.STATE_USER_SETUP_FINALIZED:
// Cannot transition out of finalized.
break;
+ case DevicePolicyManager.STATE_USER_PROFILE_FINALIZED:
+ // Should only move to an unmanaged state after removing the work profile.
+ if (newState == DevicePolicyManager.STATE_USER_UNMANAGED) {
+ return;
+ }
+ break;
}
// Didn't meet any of the accepted state transition checks above, throw appropriate error.
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index 7654093..d55bbd1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -468,8 +468,9 @@
TEST_CALLING_UID);
}
- private void setPrioritizedAlarm(int type, long triggerTime, IAlarmListener listener) {
- mService.setImpl(type, triggerTime, WINDOW_EXACT, 0, null, listener, "test",
+ private void setPrioritizedAlarm(int type, long triggerTime, long windowLength,
+ IAlarmListener listener) {
+ mService.setImpl(type, triggerTime, windowLength, 0, null, listener, "test",
FLAG_STANDALONE | FLAG_PRIORITIZE, null, null, TEST_CALLING_UID,
TEST_CALLING_PACKAGE, null);
}
@@ -1685,7 +1686,7 @@
final int numAlarms = 10;
for (int i = 0; i < numAlarms; i++) {
setPrioritizedAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + i,
- new IAlarmListener.Stub() {
+ 0, new IAlarmListener.Stub() {
@Override
public void doAlarm(IAlarmCompleteListener callback)
throws RemoteException {
@@ -1720,7 +1721,7 @@
final int numAlarms = 10;
for (int i = 0; i < numAlarms; i++) {
setPrioritizedAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + i,
- new IAlarmListener.Stub() {
+ 0, new IAlarmListener.Stub() {
@Override
public void doAlarm(IAlarmCompleteListener callback)
throws RemoteException {
@@ -1738,12 +1739,12 @@
}
assertEquals(numAlarms, alarmsFired.get());
- setPrioritizedAlarm(ELAPSED_REALTIME_WAKEUP, idleUntil - 3, new IAlarmListener.Stub() {
+ setPrioritizedAlarm(ELAPSED_REALTIME_WAKEUP, idleUntil - 3, 0, new IAlarmListener.Stub() {
@Override
public void doAlarm(IAlarmCompleteListener callback) throws RemoteException {
}
});
- setPrioritizedAlarm(ELAPSED_REALTIME_WAKEUP, idleUntil - 2, new IAlarmListener.Stub() {
+ setPrioritizedAlarm(ELAPSED_REALTIME_WAKEUP, idleUntil - 2, 0, new IAlarmListener.Stub() {
@Override
public void doAlarm(IAlarmCompleteListener callback) throws RemoteException {
}
@@ -2263,6 +2264,28 @@
}
@Test
+ public void minWindowPriorityAlarm() {
+ doReturn(true).when(
+ () -> CompatChanges.isChangeEnabled(
+ eq(AlarmManager.ENFORCE_MINIMUM_WINDOW_ON_INEXACT_ALARMS),
+ anyString(), any(UserHandle.class)));
+ final long minWindow = 73;
+ setDeviceConfigLong(KEY_MIN_WINDOW, minWindow);
+
+ // 0 is WINDOW_EXACT and < 0 is WINDOW_HEURISTIC.
+ for (int window = 1; window <= minWindow; window++) {
+ setPrioritizedAlarm(ELAPSED_REALTIME, 0, window, new IAlarmListener.Stub() {
+ @Override
+ public void doAlarm(IAlarmCompleteListener callback) throws RemoteException {
+ }
+ });
+ assertEquals(1, mService.mAlarmStore.size());
+ final Alarm a = mService.mAlarmStore.remove(unused -> true).get(0);
+ assertEquals(window, a.windowLength);
+ }
+ }
+
+ @Test
public void denyListPackagesAdded() {
mService.mConstants.EXACT_ALARM_DENY_LIST = new ArraySet<>(new String[]{"p1", "p2", "p3"});
setDeviceConfigString(KEY_EXACT_ALARM_DENY_LIST, "p2,p4,p5");
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 89798ce..1b42dfa 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -3179,6 +3179,16 @@
}
@Test
+ public void testSetUserProvisioningState_profileFinalized_canTransitionToUserUnmanaged()
+ throws Exception {
+ setupProfileOwner();
+
+ exerciseUserProvisioningTransitions(CALLER_USER_HANDLE,
+ DevicePolicyManager.STATE_USER_PROFILE_FINALIZED,
+ DevicePolicyManager.STATE_USER_UNMANAGED);
+ }
+
+ @Test
public void testSetUserProvisioningState_illegalTransitionToAnotherInProgressState()
throws Exception {
setupProfileOwner();
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index 4a42940..5d60a89 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -208,4 +208,9 @@
parcel.recycle();
}
}
-}
+
+ @Override
+ void setKeystorePassword(byte[] password, int userHandle) {
+
+ }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java b/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java
index 2b9a05c..efa1b04 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java
@@ -20,11 +20,16 @@
import android.app.NotificationManager;
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
+import android.os.Handler;
+import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
@@ -94,4 +99,11 @@
public int checkCallingOrSelfPermission(String permission) {
return PackageManager.PERMISSION_GRANTED;
}
+
+ @Override
+ public Intent registerReceiverAsUser(BroadcastReceiver receiver,
+ UserHandle user, IntentFilter filter, String broadcastPermission,
+ Handler scheduler) {
+ return null;
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 0afd39f..2f52352 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1971,7 +1971,8 @@
// test misc display overrides
assertEquals(ignoreOrientationRequests, testDisplayContent.mIgnoreOrientationRequest);
- assertEquals(fixedOrientationLetterboxRatio, mWm.getFixedOrientationLetterboxAspectRatio(),
+ assertEquals(fixedOrientationLetterboxRatio,
+ mWm.mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio(),
0 /* delta */);
}
@@ -2011,7 +2012,8 @@
// test misc display overrides
assertEquals(ignoreOrientationRequests, testDisplayContent.mIgnoreOrientationRequest);
- assertEquals(fixedOrientationLetterboxRatio, mWm.getFixedOrientationLetterboxAspectRatio(),
+ assertEquals(fixedOrientationLetterboxRatio,
+ mWm.mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio(),
0 /* delta */);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index ee1d393..95b7443 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -335,11 +335,11 @@
final WindowState window = createWindow(null, TYPE_BASE_APPLICATION, mActivity, "window");
assertEquals(window, mActivity.findMainWindow());
- assertTrue(mActivity.isLetterboxed(mActivity.findMainWindow()));
+ assertTrue(mActivity.mLetterboxUiController.isLetterboxed(mActivity.findMainWindow()));
window.mAttrs.flags |= FLAG_SHOW_WALLPAPER;
- assertFalse(mActivity.isLetterboxed(mActivity.findMainWindow()));
+ assertFalse(mActivity.mLetterboxUiController.isLetterboxed(mActivity.findMainWindow()));
}
@Test
@@ -1023,7 +1023,7 @@
// Portrait fixed app with min aspect ratio higher that aspect ratio override for fixed
// orientation letterbox.
- mActivity.mWmService.setFixedOrientationLetterboxAspectRatio(1.1f);
+ mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.1f);
mActivity.info.setMinAspectRatio(3);
prepareUnresizable(mActivity, /* maxAspect= */ 0, SCREEN_ORIENTATION_PORTRAIT);
@@ -1054,7 +1054,7 @@
// Portrait fixed app with max aspect ratio lower that aspect ratio override for fixed
// orientation letterbox.
- mActivity.mWmService.setFixedOrientationLetterboxAspectRatio(3);
+ mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(3);
prepareUnresizable(mActivity, /* maxAspect= */ 2, SCREEN_ORIENTATION_PORTRAIT);
final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds());
@@ -1085,7 +1085,7 @@
// Portrait fixed app with min aspect ratio higher that aspect ratio override for fixed
// orientation letterbox.
final float fixedOrientationLetterboxAspectRatio = 1.1f;
- mActivity.mWmService.setFixedOrientationLetterboxAspectRatio(
+ mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(
fixedOrientationLetterboxAspectRatio);
prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
@@ -1586,7 +1586,7 @@
setUpDisplaySizeWithApp(2800, 1400);
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
- mActivity.mWmService.setLetterboxHorizontalPositionMultiplier(
+ mActivity.mWmService.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(
letterboxHorizontalPositionMultiplier);
prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
@@ -1624,7 +1624,7 @@
setUpDisplaySizeWithApp(2800, 1400);
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
- mActivity.mWmService.setLetterboxHorizontalPositionMultiplier(
+ mActivity.mWmService.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(
letterboxHorizontalPositionMultiplier);
prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
index f3616da6c..619aee6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
+++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
@@ -17,6 +17,8 @@
package com.android.server.wm;
import android.annotation.NonNull;
+import android.graphics.ColorSpace;
+import android.graphics.GraphicBuffer;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.Region;
@@ -253,4 +255,14 @@
public SurfaceControl.Transaction unsetFixedTransformHint(@NonNull SurfaceControl sc) {
return this;
}
+
+ @Override
+ public SurfaceControl.Transaction setBuffer(SurfaceControl sc, GraphicBuffer buffer) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setColorSpace(SurfaceControl sc, ColorSpace colorSpace) {
+ return this;
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index ae12062..2d4e4ef 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -208,11 +208,11 @@
// Ensure letterbox aspect ratio is not overridden on any device target.
// {@link com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio}, is set
// on some device form factors.
- mAtm.mWindowManager.setFixedOrientationLetterboxAspectRatio(0);
+ mAtm.mWindowManager.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(0);
// Ensure letterbox position multiplier is not overridden on any device target.
// {@link com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier},
// may be set on some device form factors.
- mAtm.mWindowManager.setLetterboxHorizontalPositionMultiplier(0.5f);
+ mAtm.mWindowManager.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(0.5f);
checkDeviceSpecificOverridesNotApplied();
}
@@ -220,10 +220,10 @@
@After
public void tearDown() throws Exception {
// Revert back to device overrides.
- mAtm.mWindowManager.setFixedOrientationLetterboxAspectRatio(
+ mAtm.mWindowManager.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(
mContext.getResources().getFloat(
com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio));
- mAtm.mWindowManager.setLetterboxHorizontalPositionMultiplier(
+ mAtm.mWindowManager.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(
mContext.getResources().getFloat(
com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier));
}
@@ -235,7 +235,8 @@
private void checkDeviceSpecificOverridesNotApplied() {
// Check global overrides
if (!sGlobalOverridesChecked) {
- assertEquals(0, mWm.getFixedOrientationLetterboxAspectRatio(), 0 /* delta */);
+ assertEquals(0, mWm.mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio(),
+ 0 /* delta */);
sGlobalOverridesChecked = true;
}
// Check display-specific overrides
diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
index 32533cb..0d6cd5a 100644
--- a/telephony/common/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/common/com/android/internal/telephony/SmsApplication.java
@@ -760,6 +760,7 @@
private static void assignExclusiveSmsPermissionsToSystemApp(Context context,
PackageManager packageManager, AppOpsManager appOps, String packageName,
boolean sigatureMatch) {
+ if (packageName == null) return;
// First check package signature matches the caller's package signature.
// Since this class is only used internally by the system, this check makes sure
// the package signature matches system signature.
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index bde62fb..ac01afa 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -134,7 +134,7 @@
*
* Range [0, 15] for each CQI.
*/
- private List<Integer> mCsiCqiReport;;
+ private List<Integer> mCsiCqiReport;
private int mSsRsrp;
private int mSsRsrq;
private int mSsSinr;
@@ -172,13 +172,13 @@
* @hide
*/
public CellSignalStrengthNr(int csiRsrp, int csiRsrq, int csiSinr, int csiCqiTableIndex,
- List<Integer> csiCqiReport, int ssRsrp, int ssRsrq, int ssSinr) {
+ List<Byte> csiCqiReport, int ssRsrp, int ssRsrq, int ssSinr) {
mCsiRsrp = inRangeOrUnavailable(csiRsrp, -140, -44);
mCsiRsrq = inRangeOrUnavailable(csiRsrq, -20, -3);
mCsiSinr = inRangeOrUnavailable(csiSinr, -23, 23);
mCsiCqiTableIndex = inRangeOrUnavailable(csiCqiTableIndex, 1, 3);
- mCsiCqiReport = csiCqiReport.stream()
- .map(cqi -> new Integer(inRangeOrUnavailable(cqi.intValue(), 1, 3)))
+ mCsiCqiReport = csiCqiReport.stream()
+ .map(cqi -> new Integer(inRangeOrUnavailable(Byte.toUnsignedInt(cqi), 1, 3)))
.collect(Collectors.toList());
mSsRsrp = inRangeOrUnavailable(ssRsrp, -140, -44);
mSsRsrq = inRangeOrUnavailable(ssRsrq, -43, 20);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f0771be..c8e5e56 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -4885,8 +4885,9 @@
* Return the set of IMSIs that should be considered "merged together" for data usage
* purposes. This API merges IMSIs based on subscription grouping: IMSI of those in the same
* group will all be returned.
- * Return the current IMSI if there is no subscription group. See
- * {@link SubscriptionManager#createSubscriptionGroup(List)} for the definition of a group.
+ * Return the current IMSI if there is no subscription group, see
+ * {@link SubscriptionManager#createSubscriptionGroup(List)} for the definition of a group,
+ * otherwise return an empty array if there is a failure.
*
* @hide
*/
diff --git a/telephony/java/android/telephony/data/QosBearerFilter.java b/telephony/java/android/telephony/data/QosBearerFilter.java
index 6c1c653..5642549 100644
--- a/telephony/java/android/telephony/data/QosBearerFilter.java
+++ b/telephony/java/android/telephony/data/QosBearerFilter.java
@@ -31,7 +31,6 @@
import java.util.List;
import java.util.Objects;
-
/**
* Class that stores QOS filter parameters as defined in
* 3gpp 24.008 10.5.6.12 and 3gpp 24.501 9.11.4.13.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index 0593615..a540dff 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -23,7 +23,7 @@
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.STATUS_BAR_LAYER_NAME
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.STATUS_BAR_WINDOW_NAME
-val LAUNCHER_TITLE = arrayOf("Wallpaper", "Launcher", "com.google.android.googlequicksearchbox")
+val HOME_WINDOW_TITLE = arrayOf("Wallpaper", "Launcher")
fun FlickerTestParameter.statusBarWindowIsAlwaysVisible() {
assertWm {
@@ -41,23 +41,23 @@
assertWm {
this.showsAppWindowOnTop(testApp.getPackage())
.then()
- .showsAppWindowOnTop(*LAUNCHER_TITLE)
+ .showsAppWindowOnTop(*HOME_WINDOW_TITLE)
}
}
fun FlickerTestParameter.launcherWindowBecomesVisible() {
assertWm {
- this.hidesBelowAppWindow(*LAUNCHER_TITLE)
+ this.hidesBelowAppWindow(*HOME_WINDOW_TITLE)
.then()
- .showsBelowAppWindow(*LAUNCHER_TITLE)
+ .showsBelowAppWindow(*HOME_WINDOW_TITLE)
}
}
fun FlickerTestParameter.launcherWindowBecomesInvisible() {
assertWm {
- this.showsBelowAppWindow(*LAUNCHER_TITLE)
+ this.showsBelowAppWindow(*HOME_WINDOW_TITLE)
.then()
- .hidesBelowAppWindow(*LAUNCHER_TITLE)
+ .hidesBelowAppWindow(*HOME_WINDOW_TITLE)
}
}
@@ -179,7 +179,7 @@
fun FlickerTestParameter.appLayerReplacesLauncher(appName: String) {
assertLayers {
- this.isVisible(*LAUNCHER_TITLE)
+ this.isVisible(*HOME_WINDOW_TITLE)
.then()
.isVisible(appName)
}
@@ -190,7 +190,7 @@
this.isVisible(testApp.getPackage())
.then()
.isInvisible(testApp.getPackage())
- .isVisible(*LAUNCHER_TITLE)
+ .isVisible(*HOME_WINDOW_TITLE)
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
index 6a7309c..01e34d9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
@@ -18,11 +18,11 @@
import android.platform.helpers.IAppHelper
import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.LAUNCHER_TITLE
+import com.android.server.wm.flicker.HOME_WINDOW_TITLE
fun FlickerTestParameter.appWindowReplacesLauncherAsTopWindow(testApp: IAppHelper) {
assertWm {
- this.showsAppWindowOnTop(*LAUNCHER_TITLE)
+ this.showsAppWindowOnTop(*HOME_WINDOW_TITLE)
.then()
.showsAppWindowOnTop("Snapshot", testApp.getPackage())
}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
index f6d9a73..487c856 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
@@ -56,6 +56,7 @@
CanvasProperty<Float> mY;
CanvasProperty<Float> mRadius;
CanvasProperty<Float> mProgress;
+ CanvasProperty<Float> mNoisePhase;
CanvasProperty<Paint> mPaint;
RuntimeShader mRuntimeShader;
@@ -99,6 +100,7 @@
mY = CanvasProperty.createFloat(200.0f);
mRadius = CanvasProperty.createFloat(150.0f);
mProgress = CanvasProperty.createFloat(0.0f);
+ mNoisePhase = CanvasProperty.createFloat(0.0f);
Paint p = new Paint();
p.setAntiAlias(true);
@@ -115,7 +117,8 @@
if (canvas.isHardwareAccelerated()) {
RecordingCanvas recordingCanvas = (RecordingCanvas) canvas;
- recordingCanvas.drawRipple(mX, mY, mRadius, mPaint, mProgress, mRuntimeShader);
+ recordingCanvas.drawRipple(mX, mY, mRadius, mPaint, mProgress, mNoisePhase,
+ mRuntimeShader);
}
}
@@ -141,6 +144,9 @@
mProgress, mToggle ? 1.0f : 0.0f));
mRunningAnimations.add(new RenderNodeAnimator(
+ mNoisePhase, DURATION));
+
+ mRunningAnimations.add(new RenderNodeAnimator(
mPaint, RenderNodeAnimator.PAINT_ALPHA, 64.0f));
// Will be "chained" to run after the above
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index 6d852bf..9b74583 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -312,7 +312,7 @@
.addCapability(NET_CAPABILITY_EIMS)
.addCapability(NET_CAPABILITY_NOT_METERED);
if (isAtLeastS()) {
- netCap.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2));
+ netCap.setSubscriptionIds(Set.of(TEST_SUBID1, TEST_SUBID2));
netCap.setUids(uids);
}
if (isAtLeastR()) {
@@ -642,16 +642,16 @@
assertTrue(nc2.appliesToUid(22));
// Verify the subscription id list can be combined only when they are equal.
- nc1.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2));
- nc2.setSubIds(Set.of(TEST_SUBID2));
+ nc1.setSubscriptionIds(Set.of(TEST_SUBID1, TEST_SUBID2));
+ nc2.setSubscriptionIds(Set.of(TEST_SUBID2));
assertThrows(IllegalStateException.class, () -> nc2.combineCapabilities(nc1));
- nc2.setSubIds(Set.of());
+ nc2.setSubscriptionIds(Set.of());
assertThrows(IllegalStateException.class, () -> nc2.combineCapabilities(nc1));
- nc2.setSubIds(Set.of(TEST_SUBID2, TEST_SUBID1));
+ nc2.setSubscriptionIds(Set.of(TEST_SUBID2, TEST_SUBID1));
nc2.combineCapabilities(nc1);
- assertEquals(Set.of(TEST_SUBID2, TEST_SUBID1), nc2.getSubIds());
+ assertEquals(Set.of(TEST_SUBID2, TEST_SUBID1), nc2.getSubscriptionIds());
}
}
@@ -806,20 +806,20 @@
assertEquals(nc1, nc2);
if (isAtLeastS()) {
- assertThrows(NullPointerException.class, () -> nc1.setSubIds(null));
- nc1.setSubIds(Set.of());
+ assertThrows(NullPointerException.class, () -> nc1.setSubscriptionIds(null));
+ nc1.setSubscriptionIds(Set.of());
nc2.set(nc1);
assertEquals(nc1, nc2);
- nc1.setSubIds(Set.of(TEST_SUBID1));
+ nc1.setSubscriptionIds(Set.of(TEST_SUBID1));
nc2.set(nc1);
assertEquals(nc1, nc2);
- nc2.setSubIds(Set.of(TEST_SUBID2, TEST_SUBID1));
+ nc2.setSubscriptionIds(Set.of(TEST_SUBID2, TEST_SUBID1));
nc2.set(nc1);
assertEquals(nc1, nc2);
- nc2.setSubIds(Set.of(TEST_SUBID3, TEST_SUBID2));
+ nc2.setSubscriptionIds(Set.of(TEST_SUBID3, TEST_SUBID2));
assertNotEquals(nc1, nc2);
}
}
@@ -908,8 +908,8 @@
// satisfy these requests.
final NetworkCapabilities nc = new NetworkCapabilities.Builder()
.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
- .setSubIds(new ArraySet<>(subIds)).build();
- assertEquals(new ArraySet<>(subIds), nc.getSubIds());
+ .setSubscriptionIds(new ArraySet<>(subIds)).build();
+ assertEquals(new ArraySet<>(subIds), nc.getSubscriptionIds());
return nc;
}
@@ -921,11 +921,11 @@
final NetworkCapabilities ncWithoutRequestedIds = capsWithSubIds(TEST_SUBID3);
final NetworkRequest requestWithoutId = new NetworkRequest.Builder().build();
- assertEmpty(requestWithoutId.networkCapabilities.getSubIds());
+ assertEmpty(requestWithoutId.networkCapabilities.getSubscriptionIds());
final NetworkRequest requestWithIds = new NetworkRequest.Builder()
- .setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2)).build();
+ .setSubscriptionIds(Set.of(TEST_SUBID1, TEST_SUBID2)).build();
assertEquals(Set.of(TEST_SUBID1, TEST_SUBID2),
- requestWithIds.networkCapabilities.getSubIds());
+ requestWithIds.networkCapabilities.getSubscriptionIds());
assertFalse(requestWithIds.canBeSatisfiedBy(ncWithoutId));
assertTrue(requestWithIds.canBeSatisfiedBy(ncWithOtherIds));
@@ -1138,8 +1138,8 @@
if (isAtLeastS()) {
final NetworkCapabilities nc2 = new NetworkCapabilities.Builder()
- .setSubIds(Set.of(TEST_SUBID1)).build();
- assertEquals(Set.of(TEST_SUBID1), nc2.getSubIds());
+ .setSubscriptionIds(Set.of(TEST_SUBID1)).build();
+ assertEquals(Set.of(TEST_SUBID1), nc2.getSubscriptionIds());
}
}
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 039ce2f..b71be59 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -2668,25 +2668,6 @@
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- // Bring up wifi with a score of 70.
- // Cell is lingered because it would not satisfy any request, even if it validated.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.adjustScore(50);
- mWiFiNetworkAgent.connect(false); // Score: 70
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Tear down wifi.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
// Bring up wifi, then validate it. Previous versions would immediately tear down cell, but
// it's arguably correct to linger it, since it was the default network before it validated.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
@@ -2991,11 +2972,17 @@
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- // BUG: the network will no longer linger, even though it's validated and outscored.
- // TODO: fix this.
mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
mEthernetNetworkAgent.connect(true);
+ // BUG: with the legacy int-based scoring code, the network will no longer linger, even
+ // though it's validated and outscored.
+ // The new policy-based scoring code fixes this.
+ // TODO: remove the line below and replace with the three commented lines when
+ // the policy-based scoring code is turned on.
callback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
+ // callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
+ // callback.expectCallback(CallbackEntry.LOSING, mWiFiNetworkAgent);
+ // callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
callback.assertNoCallback();
@@ -12602,12 +12589,12 @@
public void testSubIdsClearedWithoutNetworkFactoryPermission() throws Exception {
mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_DENIED);
final NetworkCapabilities nc = new NetworkCapabilities();
- nc.setSubIds(Collections.singleton(Process.myUid()));
+ nc.setSubscriptionIds(Collections.singleton(Process.myUid()));
final NetworkCapabilities result =
mService.networkCapabilitiesRestrictedForCallerPermissions(
nc, Process.myPid(), Process.myUid());
- assertTrue(result.getSubIds().isEmpty());
+ assertTrue(result.getSubscriptionIds().isEmpty());
}
@Test
@@ -12616,17 +12603,17 @@
final Set<Integer> subIds = Collections.singleton(Process.myUid());
final NetworkCapabilities nc = new NetworkCapabilities();
- nc.setSubIds(subIds);
+ nc.setSubscriptionIds(subIds);
final NetworkCapabilities result =
mService.networkCapabilitiesRestrictedForCallerPermissions(
nc, Process.myPid(), Process.myUid());
- assertEquals(subIds, result.getSubIds());
+ assertEquals(subIds, result.getSubscriptionIds());
}
private NetworkRequest getRequestWithSubIds() {
return new NetworkRequest.Builder()
- .setSubIds(Collections.singleton(Process.myUid()))
+ .setSubscriptionIds(Collections.singleton(Process.myUid()))
.build();
}
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 9a66343..907cb46 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -696,7 +696,7 @@
.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.addTransportType(transport);
if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- ncBuilder.setSubIds(Collections.singleton(subId));
+ ncBuilder.setSubscriptionIds(Collections.singleton(subId));
}
return ncBuilder;
diff --git a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
index 0c7363e..8289e85 100644
--- a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
@@ -189,7 +189,7 @@
private NetworkRequest getWifiRequest(Set<Integer> netCapsSubIds) {
return getExpectedRequestBase()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .setSubIds(netCapsSubIds)
+ .setSubscriptionIds(netCapsSubIds)
.build();
}
@@ -201,7 +201,7 @@
}
private NetworkRequest getRouteSelectionRequest(Set<Integer> netCapsSubIds) {
- return getExpectedRequestBase().setSubIds(netCapsSubIds).build();
+ return getExpectedRequestBase().setSubscriptionIds(netCapsSubIds).build();
}
private NetworkRequest.Builder getExpectedRequestBase() {
diff --git a/tools/hiddenapi/checksorted_sha.sh b/tools/hiddenapi/checksorted_sha.sh
deleted file mode 100755
index 72fb867..0000000
--- a/tools/hiddenapi/checksorted_sha.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-set -e
-LOCAL_DIR="$( dirname ${BASH_SOURCE} )"
-git show --name-only --pretty=format: $1 | grep "hiddenapi/hiddenapi-.*txt" | while read file; do
- diff <(git show $1:$file) <(git show $1:$file | $LOCAL_DIR/sort_api.sh ) || {
- echo -e "\e[1m\e[31m$file $1 is not sorted or contains duplicates. To sort it correctly:\e[0m"
- echo -e "\e[33m${LOCAL_DIR}/sort_api.sh $PWD/$file\e[0m"
- exit 1
- }
-done
diff --git a/tools/hiddenapi/sort_api.sh b/tools/hiddenapi/sort_api.sh
deleted file mode 100755
index 710da40..0000000
--- a/tools/hiddenapi/sort_api.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/bash
-set -e
-if [ -z "$1" ]; then
- source_list=/dev/stdin
- dest_list=/dev/stdout
-else
- source_list="$1"
- dest_list="$1"
-fi
-# Load the file
-readarray A < "$source_list"
-# Sort
-IFS=$'\n'
-# Stash away comments
-C=( $(grep -E '^#' <<< "${A[*]}" || :) )
-A=( $(grep -v -E '^#' <<< "${A[*]}" || :) )
-# Sort entries
-A=( $(LC_COLLATE=C sort -f <<< "${A[*]}") )
-A=( $(uniq <<< "${A[*]}") )
-# Concatenate comments and entries
-A=( ${C[*]} ${A[*]} )
-unset IFS
-# Dump array back into the file
-if [ ${#A[@]} -ne 0 ]; then
- printf '%s\n' "${A[@]}" > "$dest_list"
-fi
diff --git a/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java b/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
index da0571ba..3b75660 100644
--- a/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
+++ b/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
@@ -117,13 +117,13 @@
/**
* Interface used to listen country code event
*/
- public interface CountryCodeChangeListener {
+ public interface CountryCodeChangedListener {
/**
* Called when country code changed.
*
- * @param countryCode A new country code which is 2-Character alphanumeric.
+ * @param countryCode An ISO-3166-alpha2 country code which is 2-Character alphanumeric.
*/
- void onChanged(@NonNull String countryCode);
+ void onCountryCodeChanged(@NonNull String countryCode);
}
/**
@@ -163,27 +163,27 @@
/** @hide */
@VisibleForTesting
public class WificondEventHandler extends IWificondEventCallback.Stub {
- private Map<CountryCodeChangeListener, Executor> mCountryCodeChangeListenerHolder =
+ private Map<CountryCodeChangedListener, Executor> mCountryCodeChangedListenerHolder =
new HashMap<>();
/**
- * Register CountryCodeChangeListener with pid.
+ * Register CountryCodeChangedListener with pid.
*
* @param executor The Executor on which to execute the callbacks.
* @param listener listener for country code changed events.
*/
- public void registerCountryCodeChangeListener(Executor executor,
- CountryCodeChangeListener listener) {
- mCountryCodeChangeListenerHolder.put(listener, executor);
+ public void registerCountryCodeChangedListener(Executor executor,
+ CountryCodeChangedListener listener) {
+ mCountryCodeChangedListenerHolder.put(listener, executor);
}
/**
- * Unregister CountryCodeChangeListener with pid.
+ * Unregister CountryCodeChangedListener with pid.
*
* @param listener listener which registered country code changed events.
*/
- public void unregisterCountryCodeChangeListener(CountryCodeChangeListener listener) {
- mCountryCodeChangeListenerHolder.remove(listener);
+ public void unregisterCountryCodeChangedListener(CountryCodeChangedListener listener) {
+ mCountryCodeChangedListenerHolder.remove(listener);
}
@Override
@@ -191,8 +191,8 @@
Log.d(TAG, "OnRegDomainChanged " + countryCode);
final long token = Binder.clearCallingIdentity();
try {
- mCountryCodeChangeListenerHolder.forEach((listener, executor) -> {
- executor.execute(() -> listener.onChanged(countryCode));
+ mCountryCodeChangedListenerHolder.forEach((listener, executor) -> {
+ executor.execute(() -> listener.onCountryCodeChanged(countryCode));
});
} finally {
Binder.restoreCallingIdentity(token);
@@ -1240,25 +1240,25 @@
* @param listener listener for country code changed events.
* @return true on success, false on failure.
*/
- public boolean registerCountryCodeChangeListener(@NonNull @CallbackExecutor Executor executor,
- @NonNull CountryCodeChangeListener listener) {
+ public boolean registerCountryCodeChangedListener(@NonNull @CallbackExecutor Executor executor,
+ @NonNull CountryCodeChangedListener listener) {
if (!retrieveWificondAndRegisterForDeath()) {
return false;
}
Log.d(TAG, "registerCountryCodeEventListener called");
- mWificondEventHandler.registerCountryCodeChangeListener(executor, listener);
+ mWificondEventHandler.registerCountryCodeChangedListener(executor, listener);
return true;
}
/**
- * Unregister CountryCodeChangeListener with pid.
+ * Unregister CountryCodeChangedListener with pid.
*
* @param listener listener which registered country code changed events.
*/
- public void unregisterCountryCodeChangeListener(@NonNull CountryCodeChangeListener listener) {
+ public void unregisterCountryCodeChangedListener(@NonNull CountryCodeChangedListener listener) {
Log.d(TAG, "unregisterCountryCodeEventListener called");
- mWificondEventHandler.unregisterCountryCodeChangeListener(listener);
+ mWificondEventHandler.unregisterCountryCodeChangedListener(listener);
}
/**
diff --git a/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java b/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java
index 98a0042..3fb2301 100644
--- a/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java
@@ -98,9 +98,9 @@
@Mock
private WifiNl80211Manager.PnoScanRequestCallback mPnoScanRequestCallback;
@Mock
- private WifiNl80211Manager.CountryCodeChangeListener mCountryCodeChangeListener;
+ private WifiNl80211Manager.CountryCodeChangedListener mCountryCodeChangedListener;
@Mock
- private WifiNl80211Manager.CountryCodeChangeListener mCountryCodeChangeListener2;
+ private WifiNl80211Manager.CountryCodeChangedListener mCountryCodeChangedListener2;
@Mock
private Context mContext;
private TestLooper mLooper;
@@ -768,25 +768,25 @@
}
/**
- * Ensures callback works after register CountryCodeChangeListener.
+ * Ensures callback works after register CountryCodeChangedListener.
*/
@Test
- public void testCountryCodeChangeListenerInvocation() throws Exception {
- assertTrue(mWificondControl.registerCountryCodeChangeListener(
- Runnable::run, mCountryCodeChangeListener));
- assertTrue(mWificondControl.registerCountryCodeChangeListener(
- Runnable::run, mCountryCodeChangeListener2));
+ public void testCountryCodeChangedListenerInvocation() throws Exception {
+ assertTrue(mWificondControl.registerCountryCodeChangedListener(
+ Runnable::run, mCountryCodeChangedListener));
+ assertTrue(mWificondControl.registerCountryCodeChangedListener(
+ Runnable::run, mCountryCodeChangedListener2));
mWificondEventHandler.OnRegDomainChanged(TEST_COUNTRY_CODE);
- verify(mCountryCodeChangeListener).onChanged(TEST_COUNTRY_CODE);
- verify(mCountryCodeChangeListener2).onChanged(TEST_COUNTRY_CODE);
+ verify(mCountryCodeChangedListener).onCountryCodeChanged(TEST_COUNTRY_CODE);
+ verify(mCountryCodeChangedListener2).onCountryCodeChanged(TEST_COUNTRY_CODE);
- reset(mCountryCodeChangeListener);
- reset(mCountryCodeChangeListener2);
- mWificondControl.unregisterCountryCodeChangeListener(mCountryCodeChangeListener2);
+ reset(mCountryCodeChangedListener);
+ reset(mCountryCodeChangedListener2);
+ mWificondControl.unregisterCountryCodeChangedListener(mCountryCodeChangedListener2);
mWificondEventHandler.OnRegDomainChanged(TEST_COUNTRY_CODE);
- verify(mCountryCodeChangeListener).onChanged(TEST_COUNTRY_CODE);
- verify(mCountryCodeChangeListener2, never()).onChanged(TEST_COUNTRY_CODE);
+ verify(mCountryCodeChangedListener).onCountryCodeChanged(TEST_COUNTRY_CODE);
+ verify(mCountryCodeChangedListener2, never()).onCountryCodeChanged(TEST_COUNTRY_CODE);
}
/**