Merge "Revert "Add interval for relayout perf test"" into sc-v2-dev
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 941a1fa..44c55c2 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -410,7 +410,7 @@
],
static_libs: [
"android-non-updatable.stubs.module_lib",
- "art.module.public.api.stubs",
+ "art.module.public.api.stubs.module_lib",
],
dist: {
dir: "apistubs/android/module-lib",
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
index a2dc1c2..452bb0a 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
@@ -29,6 +29,7 @@
import android.view.InputChannel;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
@@ -82,7 +83,7 @@
private static class TestWindow extends BaseIWindow {
final WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams();
- final InsetsState mRequestedVisibility = new InsetsState();
+ final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
final InsetsState mOutInsetsState = new InsetsState();
final InsetsSourceControl[] mOutControls = new InsetsSourceControl[0];
@@ -102,7 +103,7 @@
long startTime = SystemClock.elapsedRealtimeNanos();
session.addToDisplay(this, mLayoutParams, View.VISIBLE,
- Display.DEFAULT_DISPLAY, mRequestedVisibility, inputChannel,
+ Display.DEFAULT_DISPLAY, mRequestedVisibilities, inputChannel,
mOutInsetsState, mOutControls);
final long elapsedTimeNsOfAdd = SystemClock.elapsedRealtimeNanos() - startTime;
state.addExtraResult("add", elapsedTimeNsOfAdd);
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java
index c44fd40..29048b2 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java
@@ -81,6 +81,14 @@
"sampling_interval_for_batch_call_stats";
public static final String KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS =
"sampling_interval_for_put_document_stats";
+ public static final String KEY_SAMPLING_INTERVAL_FOR_INITIALIZE_STATS =
+ "sampling_interval_for_initialize_stats";
+ public static final String KEY_SAMPLING_INTERVAL_FOR_SEARCH_STATS =
+ "sampling_interval_for_search_stats";
+ public static final String KEY_SAMPLING_INTERVAL_FOR_GLOBAL_SEARCH_STATS =
+ "sampling_interval_for_global_search_stats";
+ public static final String KEY_SAMPLING_INTERVAL_FOR_OPTIMIZE_STATS =
+ "sampling_interval_for_optimize_stats";
public static final String KEY_LIMIT_CONFIG_MAX_DOCUMENT_SIZE_BYTES =
"limit_config_max_document_size_bytes";
public static final String KEY_LIMIT_CONFIG_MAX_DOCUMENT_COUNT =
@@ -95,6 +103,10 @@
KEY_SAMPLING_INTERVAL_DEFAULT,
KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS,
KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS,
+ KEY_SAMPLING_INTERVAL_FOR_INITIALIZE_STATS,
+ KEY_SAMPLING_INTERVAL_FOR_SEARCH_STATS,
+ KEY_SAMPLING_INTERVAL_FOR_GLOBAL_SEARCH_STATS,
+ KEY_SAMPLING_INTERVAL_FOR_OPTIMIZE_STATS,
KEY_LIMIT_CONFIG_MAX_DOCUMENT_SIZE_BYTES,
KEY_LIMIT_CONFIG_MAX_DOCUMENT_COUNT,
KEY_BYTES_OPTIMIZE_THRESHOLD,
@@ -245,6 +257,58 @@
}
}
+ /**
+ * Returns cached value for sampling interval for initialize.
+ *
+ * <p>For example, sampling_interval=10 means that one out of every 10 stats was logged.
+ */
+ public int getCachedSamplingIntervalForInitializeStats() {
+ synchronized (mLock) {
+ throwIfClosedLocked();
+ return mBundleLocked.getInt(KEY_SAMPLING_INTERVAL_FOR_INITIALIZE_STATS,
+ getCachedSamplingIntervalDefault());
+ }
+ }
+
+ /**
+ * Returns cached value for sampling interval for search.
+ *
+ * <p>For example, sampling_interval=10 means that one out of every 10 stats was logged.
+ */
+ public int getCachedSamplingIntervalForSearchStats() {
+ synchronized (mLock) {
+ throwIfClosedLocked();
+ return mBundleLocked.getInt(KEY_SAMPLING_INTERVAL_FOR_SEARCH_STATS,
+ getCachedSamplingIntervalDefault());
+ }
+ }
+
+ /**
+ * Returns cached value for sampling interval for globalSearch.
+ *
+ * <p>For example, sampling_interval=10 means that one out of every 10 stats was logged.
+ */
+ public int getCachedSamplingIntervalForGlobalSearchStats() {
+ synchronized (mLock) {
+ throwIfClosedLocked();
+ return mBundleLocked.getInt(KEY_SAMPLING_INTERVAL_FOR_GLOBAL_SEARCH_STATS,
+ getCachedSamplingIntervalDefault());
+ }
+ }
+
+ /**
+ * Returns cached value for sampling interval for optimize.
+ *
+ * <p>For example, sampling_interval=10 means that one out of every 10 stats was logged.
+ */
+ public int getCachedSamplingIntervalForOptimizeStats() {
+ synchronized (mLock) {
+ throwIfClosedLocked();
+ return mBundleLocked.getInt(KEY_SAMPLING_INTERVAL_FOR_OPTIMIZE_STATS,
+ getCachedSamplingIntervalDefault());
+ }
+ }
+
/** Returns the maximum serialized size an indexed document can be, in bytes. */
public int getCachedLimitConfigMaxDocumentSizeBytes() {
synchronized (mLock) {
@@ -343,6 +407,10 @@
case KEY_SAMPLING_INTERVAL_DEFAULT:
case KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS:
case KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS:
+ case KEY_SAMPLING_INTERVAL_FOR_INITIALIZE_STATS:
+ case KEY_SAMPLING_INTERVAL_FOR_SEARCH_STATS:
+ case KEY_SAMPLING_INTERVAL_FOR_GLOBAL_SEARCH_STATS:
+ case KEY_SAMPLING_INTERVAL_FOR_OPTIMIZE_STATS:
synchronized (mLock) {
mBundleLocked.putInt(key, properties.getInt(key, DEFAULT_SAMPLING_INTERVAL));
}
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 1d66beb..db23a6d 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -59,6 +59,7 @@
import com.android.server.LocalManagerRegistry;
import com.android.server.SystemService;
import com.android.server.appsearch.external.localstorage.stats.CallStats;
+import com.android.server.appsearch.external.localstorage.stats.OptimizeStats;
import com.android.server.appsearch.external.localstorage.visibilitystore.VisibilityStore;
import com.android.server.appsearch.stats.StatsCollector;
import com.android.server.appsearch.util.PackageUtil;
@@ -1479,20 +1480,42 @@
private void checkForOptimize(AppSearchUserInstance instance, int mutateBatchSize) {
EXECUTOR.execute(() -> {
+ long totalLatencyStartMillis = SystemClock.elapsedRealtime();
+ OptimizeStats.Builder builder = new OptimizeStats.Builder();
try {
- instance.getAppSearchImpl().checkForOptimize(mutateBatchSize);
+ instance.getAppSearchImpl().checkForOptimize(mutateBatchSize, builder);
} catch (AppSearchException e) {
Log.w(TAG, "Error occurred when check for optimize", e);
+ } finally {
+ OptimizeStats oStats = builder
+ .setTotalLatencyMillis(
+ (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis))
+ .build();
+ if (oStats.getOriginalDocumentCount() > 0) {
+ // see if optimize has been run by checking originalDocumentCount
+ instance.getLogger().logStats(oStats);
+ }
}
});
}
private void checkForOptimize(AppSearchUserInstance instance) {
EXECUTOR.execute(() -> {
+ long totalLatencyStartMillis = SystemClock.elapsedRealtime();
+ OptimizeStats.Builder builder = new OptimizeStats.Builder();
try {
- instance.getAppSearchImpl().checkForOptimize();
+ instance.getAppSearchImpl().checkForOptimize(builder);
} catch (AppSearchException e) {
Log.w(TAG, "Error occurred when check for optimize", e);
+ } finally {
+ OptimizeStats oStats = builder
+ .setTotalLatencyMillis(
+ (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis))
+ .build();
+ if (oStats.getOriginalDocumentCount() > 0) {
+ // see if optimize has been run by checking originalDocumentCount
+ instance.getLogger().logStats(oStats);
+ }
}
});
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
index 830e76c..15916cc 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
@@ -55,6 +55,7 @@
import com.android.server.appsearch.external.localstorage.converter.SetSchemaResponseToProtoConverter;
import com.android.server.appsearch.external.localstorage.converter.TypePropertyPathToProtoConverter;
import com.android.server.appsearch.external.localstorage.stats.InitializeStats;
+import com.android.server.appsearch.external.localstorage.stats.OptimizeStats;
import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
import com.android.server.appsearch.external.localstorage.stats.SearchStats;
@@ -145,6 +146,9 @@
public final class AppSearchImpl implements Closeable {
private static final String TAG = "AppSearchImpl";
+ /** A value 0 means that there're no more pages in the search results. */
+ private static final long EMPTY_PAGE_TOKEN = 0;
+
@VisibleForTesting static final int CHECK_OPTIMIZE_INTERVAL = 100;
private final ReadWriteLock mReadWriteLock = new ReentrantReadWriteLock();
@@ -284,6 +288,9 @@
// Log the time it took to read the data that goes into the cache maps
if (initStatsBuilder != null) {
+ // In case there is some error for getAllNamespaces, we can still
+ // set the latency for preparation.
+ // If there is no error, the value will be overridden by the actual one later.
initStatsBuilder
.setStatusCode(
statusProtoToResultCode(
@@ -1135,6 +1142,16 @@
searchResultProto.getResultsCount(),
searchResultProto);
checkSuccess(searchResultProto.getStatus());
+ if (nextPageToken != EMPTY_PAGE_TOKEN
+ && searchResultProto.getNextPageToken() == EMPTY_PAGE_TOKEN) {
+ // At this point, we're guaranteed that this nextPageToken exists for this package,
+ // otherwise checkNextPageToken would've thrown an exception.
+ // Since the new token is 0, this is the last page. We should remove the old token
+ // from our cache since it no longer refers to this query.
+ synchronized (mNextPageTokensLocked) {
+ mNextPageTokensLocked.get(packageName).remove(nextPageToken);
+ }
+ }
return rewriteSearchResultProto(searchResultProto, mSchemaMapLocked);
} finally {
mReadWriteLock.readLock().unlock();
@@ -1326,8 +1343,7 @@
deleteResultProto.getStatus(), StatusProto.Code.OK, StatusProto.Code.NOT_FOUND);
// Update derived maps
- int numDocumentsDeleted =
- deleteResultProto.getDeleteStats().getNumDocumentsDeleted();
+ int numDocumentsDeleted = deleteResultProto.getDeleteStats().getNumDocumentsDeleted();
updateDocumentCountAfterRemovalLocked(packageName, numDocumentsDeleted);
} finally {
mReadWriteLock.writeLock().unlock();
@@ -2056,6 +2072,10 @@
}
private void addNextPageToken(String packageName, long nextPageToken) {
+ if (nextPageToken == EMPTY_PAGE_TOKEN) {
+ // There is no more pages. No need to add it.
+ return;
+ }
synchronized (mNextPageTokensLocked) {
Set<Long> tokens = mNextPageTokensLocked.get(packageName);
if (tokens == null) {
@@ -2068,6 +2088,11 @@
private void checkNextPageToken(String packageName, long nextPageToken)
throws AppSearchException {
+ if (nextPageToken == EMPTY_PAGE_TOKEN) {
+ // Swallow the check for empty page token, token = 0 means there is no more page and it
+ // won't return anything from Icing.
+ return;
+ }
synchronized (mNextPageTokensLocked) {
Set<Long> nextPageTokens = mNextPageTokensLocked.get(packageName);
if (nextPageTokens == null || !nextPageTokens.contains(nextPageToken)) {
@@ -2162,12 +2187,13 @@
* #CHECK_OPTIMIZE_INTERVAL}, {@link IcingSearchEngine#getOptimizeInfo()} will be triggered
* and the counter will be reset.
*/
- public void checkForOptimize(int mutationSize) throws AppSearchException {
+ public void checkForOptimize(int mutationSize, @Nullable OptimizeStats.Builder builder)
+ throws AppSearchException {
mReadWriteLock.writeLock().lock();
try {
mOptimizeIntervalCountLocked += mutationSize;
if (mOptimizeIntervalCountLocked >= CHECK_OPTIMIZE_INTERVAL) {
- checkForOptimize();
+ checkForOptimize(builder);
}
} finally {
mReadWriteLock.writeLock().unlock();
@@ -2183,14 +2209,15 @@
* <p>{@link IcingSearchEngine#optimize()} should be called only if {@link
* OptimizeStrategy#shouldOptimize(GetOptimizeInfoResultProto)} return true.
*/
- public void checkForOptimize() throws AppSearchException {
+ public void checkForOptimize(@Nullable OptimizeStats.Builder builder)
+ throws AppSearchException {
mReadWriteLock.writeLock().lock();
try {
GetOptimizeInfoResultProto optimizeInfo = getOptimizeInfoResultLocked();
checkSuccess(optimizeInfo.getStatus());
mOptimizeIntervalCountLocked = 0;
if (mOptimizeStrategy.shouldOptimize(optimizeInfo)) {
- optimize();
+ optimize(builder);
}
} finally {
mReadWriteLock.writeLock().unlock();
@@ -2201,13 +2228,18 @@
}
/** Triggers {@link IcingSearchEngine#optimize()} directly. */
- public void optimize() throws AppSearchException {
+ public void optimize(@Nullable OptimizeStats.Builder builder) throws AppSearchException {
mReadWriteLock.writeLock().lock();
try {
mLogUtil.piiTrace("optimize, request");
OptimizeResultProto optimizeResultProto = mIcingSearchEngineLocked.optimize();
mLogUtil.piiTrace(
"optimize, response", optimizeResultProto.getStatus(), optimizeResultProto);
+ if (builder != null) {
+ builder.setStatusCode(statusProtoToResultCode(optimizeResultProto.getStatus()));
+ AppSearchLoggerHelper.copyNativeStats(
+ optimizeResultProto.getOptimizeStats(), builder);
+ }
checkSuccess(optimizeResultProto.getStatus());
} finally {
mReadWriteLock.writeLock().unlock();
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java
index d92f4f0..98cedc7 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java
@@ -17,10 +17,10 @@
package com.android.server.appsearch.external.localstorage;
import android.annotation.NonNull;
-import android.app.appsearch.exceptions.AppSearchException;
import com.android.server.appsearch.external.localstorage.stats.CallStats;
import com.android.server.appsearch.external.localstorage.stats.InitializeStats;
+import com.android.server.appsearch.external.localstorage.stats.OptimizeStats;
import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
import com.android.server.appsearch.external.localstorage.stats.SearchStats;
@@ -37,19 +37,22 @@
*/
public interface AppSearchLogger {
/** Logs {@link CallStats} */
- void logStats(@NonNull CallStats stats) throws AppSearchException;
+ void logStats(@NonNull CallStats stats);
/** Logs {@link PutDocumentStats} */
- void logStats(@NonNull PutDocumentStats stats) throws AppSearchException;
+ void logStats(@NonNull PutDocumentStats stats);
/** Logs {@link InitializeStats} */
- void logStats(@NonNull InitializeStats stats) throws AppSearchException;
+ void logStats(@NonNull InitializeStats stats);
/** Logs {@link SearchStats} */
- void logStats(@NonNull SearchStats stats) throws AppSearchException;
+ void logStats(@NonNull SearchStats stats);
/** Logs {@link RemoveStats} */
- void logStats(@NonNull RemoveStats stats) throws AppSearchException;
+ void logStats(@NonNull RemoveStats stats);
+
+ /** Logs {@link OptimizeStats} */
+ void logStats(@NonNull OptimizeStats stats);
// TODO(b/173532925) Add remaining logStats once we add all the stats.
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
index aa9200a..cd653e5 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
@@ -19,12 +19,14 @@
import android.annotation.NonNull;
import com.android.server.appsearch.external.localstorage.stats.InitializeStats;
+import com.android.server.appsearch.external.localstorage.stats.OptimizeStats;
import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
import com.android.server.appsearch.external.localstorage.stats.SearchStats;
import com.google.android.icing.proto.DeleteStatsProto;
import com.google.android.icing.proto.InitializeStatsProto;
+import com.google.android.icing.proto.OptimizeStatsProto;
import com.google.android.icing.proto.PutDocumentStatsProto;
import com.google.android.icing.proto.QueryStatsProto;
@@ -92,8 +94,8 @@
.setSchemaTypeCount(fromNativeStats.getNumSchemaTypes());
}
- /*
- * Copy native Query stats to buiilder.
+ /**
+ * Copies native Query stats to builder.
*
* @param fromNativeStats Stats copied from.
* @param toStatsBuilder Stats copied to.
@@ -122,8 +124,8 @@
fromNativeStats.getDocumentRetrievalLatencyMs());
}
- /*
- * Copy native Query stats to buiilder.
+ /**
+ * Copies native Delete stats to builder.
*
* @param fromNativeStats Stats copied from.
* @param toStatsBuilder Stats copied to.
@@ -138,4 +140,28 @@
.setDeleteType(fromNativeStats.getDeleteType().getNumber())
.setDeletedDocumentCount(fromNativeStats.getNumDocumentsDeleted());
}
+
+ /**
+ * Copies native {@link OptimizeStatsProto} to builder.
+ *
+ * @param fromNativeStats Stats copied from.
+ * @param toStatsBuilder Stats copied to.
+ */
+ static void copyNativeStats(
+ @NonNull OptimizeStatsProto fromNativeStats,
+ @NonNull OptimizeStats.Builder toStatsBuilder) {
+ Objects.requireNonNull(fromNativeStats);
+ Objects.requireNonNull(toStatsBuilder);
+ toStatsBuilder
+ .setNativeLatencyMillis(fromNativeStats.getLatencyMs())
+ .setDocumentStoreOptimizeLatencyMillis(
+ fromNativeStats.getDocumentStoreOptimizeLatencyMs())
+ .setIndexRestorationLatencyMillis(fromNativeStats.getIndexRestorationLatencyMs())
+ .setOriginalDocumentCount(fromNativeStats.getNumOriginalDocuments())
+ .setDeletedDocumentCount(fromNativeStats.getNumDeletedDocuments())
+ .setExpiredDocumentCount(fromNativeStats.getNumExpiredDocuments())
+ .setStorageSizeBeforeBytes(fromNativeStats.getStorageSizeBefore())
+ .setStorageSizeAfterBytes(fromNativeStats.getStorageSizeAfter())
+ .setTimeSinceLastOptimizeMillis(fromNativeStats.getTimeSinceLastOptimizeMs());
+ }
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/OptimizeStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/OptimizeStats.java
new file mode 100644
index 0000000..83bd50f
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/OptimizeStats.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright 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.appsearch.external.localstorage.stats;
+
+import android.annotation.NonNull;
+import android.app.appsearch.AppSearchResult;
+
+import java.util.Objects;
+
+/**
+ * Class holds detailed stats for Optimize.
+ *
+ * @hide
+ */
+public final class OptimizeStats {
+ /**
+ * The status code returned by {@link AppSearchResult#getResultCode()} for the call or internal
+ * state.
+ */
+ @AppSearchResult.ResultCode private final int mStatusCode;
+
+ private final int mTotalLatencyMillis;
+ private final int mNativeLatencyMillis;
+
+ // Time used to optimize the document store in millis.
+ private final int mNativeDocumentStoreOptimizeLatencyMillis;
+
+ // Time used to restore the index in millis.
+ private final int mNativeIndexRestorationLatencyMillis;
+
+ // Number of documents before the optimization.
+ private final int mNativeOriginalDocumentCount;
+
+ // Number of documents deleted during the optimization.
+ private final int mNativeDeletedDocumentCount;
+
+ // Number of documents expired during the optimization.
+ private final int mNativeExpiredDocumentCount;
+
+ // Size of storage in bytes before the optimization.
+ private final long mNativeStorageSizeBeforeBytes;
+
+ // Size of storage in bytes after the optimization.
+ private final long mNativeStorageSizeAfterBytes;
+
+ // The amount of time in millis since the last optimization ran calculated using wall clock time
+ private final long mNativeTimeSinceLastOptimizeMillis;
+
+ OptimizeStats(@NonNull Builder builder) {
+ Objects.requireNonNull(builder);
+ mStatusCode = builder.mStatusCode;
+ mTotalLatencyMillis = builder.mTotalLatencyMillis;
+ mNativeLatencyMillis = builder.mNativeLatencyMillis;
+ mNativeDocumentStoreOptimizeLatencyMillis =
+ builder.mNativeDocumentStoreOptimizeLatencyMillis;
+ mNativeIndexRestorationLatencyMillis = builder.mNativeIndexRestorationLatencyMillis;
+ mNativeOriginalDocumentCount = builder.mNativeOriginalDocumentCount;
+ mNativeDeletedDocumentCount = builder.mNativeDeletedDocumentCount;
+ mNativeExpiredDocumentCount = builder.mNativeExpiredDocumentCount;
+ mNativeStorageSizeBeforeBytes = builder.mNativeStorageSizeBeforeBytes;
+ mNativeStorageSizeAfterBytes = builder.mNativeStorageSizeAfterBytes;
+ mNativeTimeSinceLastOptimizeMillis = builder.mNativeTimeSinceLastOptimizeMillis;
+ }
+
+ /** Returns status code for this optimization. */
+ @AppSearchResult.ResultCode
+ public int getStatusCode() {
+ return mStatusCode;
+ }
+
+ /** Returns total latency of this optimization in millis. */
+ public int getTotalLatencyMillis() {
+ return mTotalLatencyMillis;
+ }
+
+ /** Returns how much time in millis spent in the native code. */
+ public int getNativeLatencyMillis() {
+ return mNativeLatencyMillis;
+ }
+
+ /** Returns time used to optimize the document store in millis. */
+ public int getDocumentStoreOptimizeLatencyMillis() {
+ return mNativeDocumentStoreOptimizeLatencyMillis;
+ }
+
+ /** Returns time used to restore the index in millis. */
+ public int getIndexRestorationLatencyMillis() {
+ return mNativeIndexRestorationLatencyMillis;
+ }
+
+ /** Returns number of documents before the optimization. */
+ public int getOriginalDocumentCount() {
+ return mNativeOriginalDocumentCount;
+ }
+
+ /** Returns number of documents deleted during the optimization. */
+ public int getDeletedDocumentCount() {
+ return mNativeDeletedDocumentCount;
+ }
+
+ /** Returns number of documents expired during the optimization. */
+ public int getExpiredDocumentCount() {
+ return mNativeExpiredDocumentCount;
+ }
+
+ /** Returns size of storage in bytes before the optimization. */
+ public long getStorageSizeBeforeBytes() {
+ return mNativeStorageSizeBeforeBytes;
+ }
+
+ /** Returns size of storage in bytes after the optimization. */
+ public long getStorageSizeAfterBytes() {
+ return mNativeStorageSizeAfterBytes;
+ }
+
+ /**
+ * Returns the amount of time in millis since the last optimization ran calculated using wall
+ * clock time.
+ */
+ public long getTimeSinceLastOptimizeMillis() {
+ return mNativeTimeSinceLastOptimizeMillis;
+ }
+
+ /** Builder for {@link RemoveStats}. */
+ public static class Builder {
+ /**
+ * The status code returned by {@link AppSearchResult#getResultCode()} for the call or
+ * internal state.
+ */
+ @AppSearchResult.ResultCode int mStatusCode;
+
+ int mTotalLatencyMillis;
+ int mNativeLatencyMillis;
+ int mNativeDocumentStoreOptimizeLatencyMillis;
+ int mNativeIndexRestorationLatencyMillis;
+ int mNativeOriginalDocumentCount;
+ int mNativeDeletedDocumentCount;
+ int mNativeExpiredDocumentCount;
+ long mNativeStorageSizeBeforeBytes;
+ long mNativeStorageSizeAfterBytes;
+ long mNativeTimeSinceLastOptimizeMillis;
+
+ /** Sets the status code. */
+ @NonNull
+ public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) {
+ mStatusCode = statusCode;
+ return this;
+ }
+
+ /** Sets total latency in millis. */
+ @NonNull
+ public Builder setTotalLatencyMillis(int totalLatencyMillis) {
+ mTotalLatencyMillis = totalLatencyMillis;
+ return this;
+ }
+
+ /** Sets native latency in millis. */
+ @NonNull
+ public Builder setNativeLatencyMillis(int nativeLatencyMillis) {
+ mNativeLatencyMillis = nativeLatencyMillis;
+ return this;
+ }
+
+ /** Sets time used to optimize the document store. */
+ @NonNull
+ public Builder setDocumentStoreOptimizeLatencyMillis(
+ int documentStoreOptimizeLatencyMillis) {
+ mNativeDocumentStoreOptimizeLatencyMillis = documentStoreOptimizeLatencyMillis;
+ return this;
+ }
+
+ /** Sets time used to restore the index. */
+ @NonNull
+ public Builder setIndexRestorationLatencyMillis(int indexRestorationLatencyMillis) {
+ mNativeIndexRestorationLatencyMillis = indexRestorationLatencyMillis;
+ return this;
+ }
+
+ /** Sets number of documents before the optimization. */
+ @NonNull
+ public Builder setOriginalDocumentCount(int originalDocumentCount) {
+ mNativeOriginalDocumentCount = originalDocumentCount;
+ return this;
+ }
+
+ /** Sets number of documents deleted during the optimization. */
+ @NonNull
+ public Builder setDeletedDocumentCount(int deletedDocumentCount) {
+ mNativeDeletedDocumentCount = deletedDocumentCount;
+ return this;
+ }
+
+ /** Sets number of documents expired during the optimization. */
+ @NonNull
+ public Builder setExpiredDocumentCount(int expiredDocumentCount) {
+ mNativeExpiredDocumentCount = expiredDocumentCount;
+ return this;
+ }
+
+ /** Sets Storage size in bytes before optimization. */
+ @NonNull
+ public Builder setStorageSizeBeforeBytes(long storageSizeBeforeBytes) {
+ mNativeStorageSizeBeforeBytes = storageSizeBeforeBytes;
+ return this;
+ }
+
+ /** Sets storage size in bytes after optimization. */
+ @NonNull
+ public Builder setStorageSizeAfterBytes(long storageSizeAfterBytes) {
+ mNativeStorageSizeAfterBytes = storageSizeAfterBytes;
+ return this;
+ }
+
+ /**
+ * Sets the amount the time since the last optimize ran calculated using wall clock time.
+ */
+ @NonNull
+ public Builder setTimeSinceLastOptimizeMillis(long timeSinceLastOptimizeMillis) {
+ mNativeTimeSinceLastOptimizeMillis = timeSinceLastOptimizeMillis;
+ return this;
+ }
+
+ /** Creates a {@link OptimizeStats}. */
+ @NonNull
+ public OptimizeStats build() {
+ return new OptimizeStats(/* builder= */ this);
+ }
+ }
+}
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 2cbce10..fdf6a00 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
@@ -32,6 +32,7 @@
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.InitializeStats;
+import com.android.server.appsearch.external.localstorage.stats.OptimizeStats;
import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
import com.android.server.appsearch.external.localstorage.stats.SearchStats;
@@ -145,7 +146,7 @@
}
@Override
- public void logStats(@NonNull InitializeStats stats) throws AppSearchException {
+ public void logStats(@NonNull InitializeStats stats) {
Objects.requireNonNull(stats);
synchronized (mLock) {
if (shouldLogForTypeLocked(CallStats.CALL_TYPE_INITIALIZE)) {
@@ -155,7 +156,7 @@
}
@Override
- public void logStats(@NonNull SearchStats stats) throws AppSearchException {
+ public void logStats(@NonNull SearchStats stats) {
Objects.requireNonNull(stats);
synchronized (mLock) {
if (shouldLogForTypeLocked(CallStats.CALL_TYPE_SEARCH)) {
@@ -165,10 +166,20 @@
}
@Override
- public void logStats(@NonNull RemoveStats stats) throws AppSearchException {
+ public void logStats(@NonNull RemoveStats stats) {
// TODO(b/173532925): Log stats
}
+ @Override
+ public void logStats(@NonNull OptimizeStats stats) {
+ Objects.requireNonNull(stats);
+ synchronized (mLock) {
+ if (shouldLogForTypeLocked(CallStats.CALL_TYPE_OPTIMIZE)) {
+ logStatsImplLocked(stats);
+ }
+ }
+ }
+
/**
* Removes cached UID for package.
*
@@ -326,6 +337,27 @@
stats.getResetStatusCode());
}
+ @GuardedBy("mLock")
+ private void logStatsImplLocked(@NonNull OptimizeStats stats) {
+ mLastPushTimeMillisLocked = SystemClock.elapsedRealtime();
+ ExtraStats extraStats = createExtraStatsLocked(/*packageName=*/ null,
+ CallStats.CALL_TYPE_OPTIMIZE);
+ AppSearchStatsLog.write(AppSearchStatsLog.APP_SEARCH_OPTIMIZE_STATS_REPORTED,
+ extraStats.mSamplingInterval,
+ extraStats.mSkippedSampleCount,
+ stats.getStatusCode(),
+ stats.getTotalLatencyMillis(),
+ stats.getNativeLatencyMillis(),
+ stats.getDocumentStoreOptimizeLatencyMillis(),
+ stats.getIndexRestorationLatencyMillis(),
+ stats.getOriginalDocumentCount(),
+ stats.getDeletedDocumentCount(),
+ stats.getExpiredDocumentCount(),
+ stats.getStorageSizeBeforeBytes(),
+ stats.getStorageSizeAfterBytes(),
+ stats.getTimeSinceLastOptimizeMillis());
+ }
+
/**
* Calculate the hash code as an integer by returning the last four bytes of its MD5.
*
@@ -464,15 +496,19 @@
return mConfig.getCachedSamplingIntervalForBatchCallStats();
case CallStats.CALL_TYPE_PUT_DOCUMENT:
return mConfig.getCachedSamplingIntervalForPutDocumentStats();
- case CallStats.CALL_TYPE_UNKNOWN:
case CallStats.CALL_TYPE_INITIALIZE:
+ return mConfig.getCachedSamplingIntervalForInitializeStats();
+ case CallStats.CALL_TYPE_SEARCH:
+ return mConfig.getCachedSamplingIntervalForSearchStats();
+ case CallStats.CALL_TYPE_GLOBAL_SEARCH:
+ return mConfig.getCachedSamplingIntervalForGlobalSearchStats();
+ case CallStats.CALL_TYPE_OPTIMIZE:
+ return mConfig.getCachedSamplingIntervalForOptimizeStats();
+ case CallStats.CALL_TYPE_UNKNOWN:
case CallStats.CALL_TYPE_SET_SCHEMA:
case CallStats.CALL_TYPE_GET_DOCUMENT:
case CallStats.CALL_TYPE_REMOVE_DOCUMENT_BY_ID:
- case CallStats.CALL_TYPE_SEARCH:
- case CallStats.CALL_TYPE_OPTIMIZE:
case CallStats.CALL_TYPE_FLUSH:
- case CallStats.CALL_TYPE_GLOBAL_SEARCH:
case CallStats.CALL_TYPE_REMOVE_DOCUMENT_BY_SEARCH:
// TODO(b/173532925) Some of them above will have dedicated sampling ratio config
default:
diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt
index 6555107..a81d7d80 100644
--- a/apex/appsearch/synced_jetpack_changeid.txt
+++ b/apex/appsearch/synced_jetpack_changeid.txt
@@ -1 +1 @@
-c7387d9b58726a23a0608a9365fb3a1b57b7b8a1
+Ie04f1ecc033faae8085afcb51eb9e40a298998d5
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 98e963e..86fa06c 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -2052,10 +2052,11 @@
+ " -- package not allowed to start");
return;
}
+ final int callerProcState = mActivityManagerInternal.getUidProcessState(callingUid);
removeLocked(operation, directReceiver, REMOVE_REASON_UNDEFINED);
incrementAlarmCount(a.uid);
setImplLocked(a);
- MetricsHelper.pushAlarmScheduled(a);
+ MetricsHelper.pushAlarmScheduled(a, callerProcState);
}
/**
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java b/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java
index 4e7311f..4c2f8d1 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java
@@ -22,6 +22,7 @@
import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__PERMISSION;
import static com.android.server.alarm.AlarmManagerService.INDEFINITE_DELAY;
+import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.StatsManager;
import android.content.Context;
@@ -93,7 +94,7 @@
}
}
- static void pushAlarmScheduled(Alarm a) {
+ static void pushAlarmScheduled(Alarm a, int callerProcState) {
FrameworkStatsLog.write(
FrameworkStatsLog.ALARM_SCHEDULED,
a.uid,
@@ -103,7 +104,8 @@
a.alarmClock != null,
a.repeatInterval != 0,
reasonToStatsReason(a.mExactAllowReason),
- AlarmManagerService.isRtc(a.type));
+ AlarmManagerService.isRtc(a.type),
+ ActivityManager.processStateAmToProto(callerProcState));
}
static void pushAlarmBatchDelivered(int numAlarms, int wakeups) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index 3fa1c12..90baa8e 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -116,6 +116,16 @@
@VisibleForTesting
int mVerb;
private boolean mCancelled;
+ /**
+ * True if the previous job on this context successfully finished (ie. called jobFinished or
+ * dequeueWork with no work left).
+ */
+ private boolean mPreviousJobHadSuccessfulFinish;
+ /**
+ * The last time a job on this context didn't finish successfully, in the elapsed realtime
+ * timebase.
+ */
+ private long mLastUnsuccessfulFinishElapsed;
/**
* All the information maintained about the job currently being executed.
@@ -439,7 +449,9 @@
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- assertCallerLocked(cb);
+ if (!assertCallerLocked(cb)) {
+ return null;
+ }
if (mVerb == VERB_STOPPING || mVerb == VERB_FINISHED) {
// This job is either all done, or on its way out. Either way, it
// should not dispatch any more work. We will pick up any remaining
@@ -465,7 +477,11 @@
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- assertCallerLocked(cb);
+ if (!assertCallerLocked(cb)) {
+ // Return true instead of false here so we don't just kick the
+ // Exception-throwing-can down the road to JobParameters.completeWork >:(
+ return true;
+ }
return mRunningJob.completeWorkLocked(workId);
}
} finally {
@@ -554,18 +570,34 @@
return true;
}
- private void assertCallerLocked(JobCallback cb) {
+ /**
+ * Will throw a {@link SecurityException} if the callback is not for the currently running job,
+ * but may decide not to throw an exception if the call from the previous job appears to be an
+ * accident.
+ *
+ * @return true if the callback is for the current job, false otherwise
+ */
+ private boolean assertCallerLocked(JobCallback cb) {
if (!verifyCallerLocked(cb)) {
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ if (!mPreviousJobHadSuccessfulFinish
+ && (nowElapsed - mLastUnsuccessfulFinishElapsed) < 15_000L) {
+ // Don't punish apps for race conditions
+ return false;
+ }
+ // It's been long enough that the app should really not be calling into JS for the
+ // stopped job.
StringBuilder sb = new StringBuilder(128);
sb.append("Caller no longer running");
if (cb.mStoppedReason != null) {
sb.append(", last stopped ");
- TimeUtils.formatDuration(sElapsedRealtimeClock.millis() - cb.mStoppedTime, sb);
+ TimeUtils.formatDuration(nowElapsed - cb.mStoppedTime, sb);
sb.append(" because: ");
sb.append(cb.mStoppedReason);
}
throw new SecurityException(sb.toString());
}
+ return true;
}
/**
@@ -911,6 +943,11 @@
applyStoppedReasonLocked(reason);
completedJob = mRunningJob;
final int internalStopReason = mParams.getInternalStopReasonCode();
+ mPreviousJobHadSuccessfulFinish =
+ (internalStopReason == JobParameters.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH);
+ if (!mPreviousJobHadSuccessfulFinish) {
+ mLastUnsuccessfulFinishElapsed = sElapsedRealtimeClock.millis();
+ }
mJobPackageTracker.noteInactive(completedJob, internalStopReason, reason);
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED,
completedJob.getSourceUid(), null, completedJob.getBatteryName(),
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 6c6e547..df670f4 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3202,6 +3202,59 @@
field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskAppearedInfo> CREATOR;
}
+ public final class TaskFragmentAppearedInfo implements android.os.Parcelable {
+ method @NonNull public android.view.SurfaceControl getLeash();
+ method @NonNull public android.window.TaskFragmentInfo getTaskFragmentInfo();
+ field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskFragmentAppearedInfo> CREATOR;
+ }
+
+ public final class TaskFragmentCreationParams implements android.os.Parcelable {
+ method @NonNull public android.os.IBinder getFragmentToken();
+ method @NonNull public android.graphics.Rect getInitialBounds();
+ method @NonNull public android.window.TaskFragmentOrganizerToken getOrganizer();
+ method @NonNull public android.os.IBinder getOwnerToken();
+ method public int getWindowingMode();
+ field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskFragmentCreationParams> CREATOR;
+ }
+
+ public static final class TaskFragmentCreationParams.Builder {
+ ctor public TaskFragmentCreationParams.Builder(@NonNull android.window.TaskFragmentOrganizerToken, @NonNull android.os.IBinder, @NonNull android.os.IBinder);
+ method @NonNull public android.window.TaskFragmentCreationParams build();
+ method @NonNull public android.window.TaskFragmentCreationParams.Builder setInitialBounds(@NonNull android.graphics.Rect);
+ method @NonNull public android.window.TaskFragmentCreationParams.Builder setWindowingMode(int);
+ }
+
+ public final class TaskFragmentInfo implements android.os.Parcelable {
+ method public boolean equalsForTaskFragmentOrganizer(@Nullable android.window.TaskFragmentInfo);
+ method @NonNull public java.util.List<android.os.IBinder> getActivities();
+ method @NonNull public android.content.res.Configuration getConfiguration();
+ method @NonNull public android.os.IBinder getFragmentToken();
+ method @NonNull public android.graphics.Point getPositionInParent();
+ method @NonNull public android.window.WindowContainerToken getToken();
+ method public int getWindowingMode();
+ method public boolean hasRunningActivity();
+ method public boolean isEmpty();
+ method public boolean isVisible();
+ field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskFragmentInfo> CREATOR;
+ }
+
+ public class TaskFragmentOrganizer extends android.window.WindowOrganizer {
+ ctor public TaskFragmentOrganizer(@NonNull java.util.concurrent.Executor);
+ method @NonNull public java.util.concurrent.Executor getExecutor();
+ method @NonNull public android.window.TaskFragmentOrganizerToken getOrganizerToken();
+ method public void onTaskFragmentAppeared(@NonNull android.window.TaskFragmentAppearedInfo);
+ method public void onTaskFragmentError(@NonNull android.os.IBinder, @NonNull Throwable);
+ method public void onTaskFragmentInfoChanged(@NonNull android.window.TaskFragmentInfo);
+ method public void onTaskFragmentParentInfoChanged(@NonNull android.os.IBinder, @NonNull android.content.res.Configuration);
+ method public void onTaskFragmentVanished(@NonNull android.window.TaskFragmentInfo);
+ method @CallSuper public void registerOrganizer();
+ method @CallSuper public void unregisterOrganizer();
+ }
+
+ public final class TaskFragmentOrganizerToken implements android.os.Parcelable {
+ field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskFragmentOrganizerToken> CREATOR;
+ }
+
public class TaskOrganizer extends android.window.WindowOrganizer {
ctor public TaskOrganizer();
method @BinderThread public void addStartingWindow(@NonNull android.window.StartingWindowInfo, @NonNull android.os.IBinder);
@@ -3230,9 +3283,13 @@
public final class WindowContainerTransaction implements android.os.Parcelable {
ctor public WindowContainerTransaction();
+ method @NonNull public android.window.WindowContainerTransaction createTaskFragment(@NonNull android.window.TaskFragmentCreationParams);
+ method @NonNull public android.window.WindowContainerTransaction deleteTaskFragment(@NonNull android.window.WindowContainerToken);
method public int describeContents();
method @NonNull public android.window.WindowContainerTransaction reorder(@NonNull android.window.WindowContainerToken, boolean);
method @NonNull public android.window.WindowContainerTransaction reparent(@NonNull android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken, boolean);
+ method @NonNull public android.window.WindowContainerTransaction reparentActivityToTaskFragment(@NonNull android.os.IBinder, @NonNull android.os.IBinder);
+ method @NonNull public android.window.WindowContainerTransaction reparentChildren(@NonNull android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken);
method @NonNull public android.window.WindowContainerTransaction reparentTasks(@Nullable android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken, @Nullable int[], @Nullable int[], boolean);
method @NonNull public android.window.WindowContainerTransaction scheduleFinishEnterPip(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect);
method @NonNull public android.window.WindowContainerTransaction setActivityWindowingMode(@NonNull android.window.WindowContainerToken, int);
@@ -3240,12 +3297,14 @@
method @NonNull public android.window.WindowContainerTransaction setAppBounds(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect);
method @NonNull public android.window.WindowContainerTransaction setBounds(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect);
method @NonNull public android.window.WindowContainerTransaction setBoundsChangeTransaction(@NonNull android.window.WindowContainerToken, @NonNull android.view.SurfaceControl.Transaction);
+ method @NonNull public android.window.WindowContainerTransaction setErrorCallbackToken(@NonNull android.os.IBinder);
method @NonNull public android.window.WindowContainerTransaction setFocusable(@NonNull android.window.WindowContainerToken, boolean);
method @NonNull public android.window.WindowContainerTransaction setHidden(@NonNull android.window.WindowContainerToken, boolean);
method @NonNull public android.window.WindowContainerTransaction setLaunchRoot(@NonNull android.window.WindowContainerToken, @Nullable int[], @Nullable int[]);
method @NonNull public android.window.WindowContainerTransaction setScreenSizeDp(@NonNull android.window.WindowContainerToken, int, int);
method @NonNull public android.window.WindowContainerTransaction setSmallestScreenWidthDp(@NonNull android.window.WindowContainerToken, int);
method @NonNull public android.window.WindowContainerTransaction setWindowingMode(@NonNull android.window.WindowContainerToken, int);
+ method @NonNull public android.window.WindowContainerTransaction startActivityInTaskFragment(@NonNull android.os.IBinder, @NonNull android.os.IBinder, @NonNull android.content.Intent, @Nullable android.os.Bundle);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.window.WindowContainerTransaction> CREATOR;
}
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 6c001f3..26c83ee 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -112,6 +112,8 @@
srcs: [
"android/os/Temperature.aidl",
"android/os/CoolingDevice.aidl",
+ "android/os/IHintManager.aidl",
+ "android/os/IHintSession.aidl",
"android/os/IThermalEventListener.aidl",
"android/os/IThermalStatusListener.aidl",
"android/os/IThermalService.aidl",
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index db5dcc5..643020a 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1539,6 +1539,17 @@
getApplication().dispatchActivityPostDestroyed(this);
}
+ private void dispatchActivityConfigurationChanged() {
+ getApplication().dispatchActivityConfigurationChanged(this);
+ Object[] callbacks = collectActivityLifecycleCallbacks();
+ if (callbacks != null) {
+ for (int i = 0; i < callbacks.length; i++) {
+ ((Application.ActivityLifecycleCallbacks) callbacks[i])
+ .onActivityConfigurationChanged(this);
+ }
+ }
+ }
+
private Object[] collectActivityLifecycleCallbacks() {
Object[] callbacks = null;
synchronized (mActivityLifecycleCallbacks) {
@@ -3028,6 +3039,8 @@
// view changes from above.
mActionBar.onConfigurationChanged(newConfig);
}
+
+ dispatchActivityConfigurationChanged();
}
/**
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index 618eda8..a1eab65 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -205,6 +205,13 @@
*/
default void onActivityPostDestroyed(@NonNull Activity activity) {
}
+
+ /**
+ * Called when the Activity configuration was changed.
+ * @hide
+ */
+ default void onActivityConfigurationChanged(@NonNull Activity activity) {
+ }
}
/**
@@ -554,6 +561,16 @@
}
}
+ /* package */ void dispatchActivityConfigurationChanged(@NonNull Activity activity) {
+ Object[] callbacks = collectActivityLifecycleCallbacks();
+ if (callbacks != null) {
+ for (int i = 0; i < callbacks.length; i++) {
+ ((ActivityLifecycleCallbacks) callbacks[i]).onActivityConfigurationChanged(
+ activity);
+ }
+ }
+ }
+
@UnsupportedAppUsage
private Object[] collectActivityLifecycleCallbacks() {
Object[] callbacks = null;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 249a606..7114d73 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -26,6 +26,7 @@
import android.annotation.Nullable;
import android.annotation.UiContext;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.AttributionSource;
import android.content.AutofillOptions;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -60,7 +61,6 @@
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.content.AttributionSource;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -3123,6 +3123,7 @@
mForceDisplayOverrideInResources = container.mForceDisplayOverrideInResources;
mIsConfigurationBasedContext = container.mIsConfigurationBasedContext;
mContextType = container.mContextType;
+ mContentCaptureOptions = container.mContentCaptureOptions;
} else {
mBasePackageName = packageInfo.mPackageName;
ApplicationInfo ainfo = packageInfo.getApplicationInfo();
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 871d48b..32ea41b 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -158,7 +158,6 @@
import android.os.IBinder;
import android.os.IDumpstate;
import android.os.IHardwarePropertiesManager;
-import android.os.IHintManager;
import android.os.IPowerManager;
import android.os.IRecoverySystem;
import android.os.ISystemUpdateManager;
@@ -600,10 +599,7 @@
@Override
public PerformanceHintManager createService(ContextImpl ctx)
throws ServiceNotFoundException {
- IBinder hintBinder = ServiceManager.getServiceOrThrow(
- Context.PERFORMANCE_HINT_SERVICE);
- IHintManager hintService = IHintManager.Stub.asInterface(hintBinder);
- return new PerformanceHintManager(hintService);
+ return PerformanceHintManager.create();
}});
registerService(Context.RECOVERY_SERVICE, RecoverySystem.class,
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 549ab6e..0e04ad3 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -10997,6 +10997,16 @@
* {@link #EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT} in the provisioning parameters.
* In that case the device owner's control will be limited do denying these permissions.
* <p>
+ * NOTE: On devices running {@link android.os.Build.VERSION_CODES#S} and above, control over
+ * the following permissions are restricted for managed profile owners:
+ * <ul>
+ * <li>Manifest.permission.READ_SMS</li>
+ * </ul>
+ * <p>
+ * A managed profile owner may not grant these permissions (i.e. call this method with any of
+ * the permissions listed above and {@code grantState} of
+ * {@code #PERMISSION_GRANT_STATE_GRANTED}), but may deny them.
+ * <p>
* Attempts by the admin to grant these permissions, when the admin is restricted from doing
* so, will be silently ignored (no exception will be thrown).
*
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index f5ab2ab..8398be1 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -3518,22 +3518,22 @@
}
/**
- * Determines whether a String Bluetooth address, such as "00:43:A8:23:10:F0"
+ * Determines whether a String Bluetooth address, such as "F0:43:A8:23:10:00"
* is a RANDOM STATIC address.
*
- * RANDOM STATIC: (addr & 0b11) == 0b11
- * RANDOM RESOLVABLE: (addr & 0b11) == 0b10
- * RANDOM non-RESOLVABLE: (addr & 0b11) == 0b00
+ * RANDOM STATIC: (addr & 0xC0) == 0xC0
+ * RANDOM RESOLVABLE: (addr & 0xC0) == 0x40
+ * RANDOM non-RESOLVABLE: (addr & 0xC0) == 0x00
*
* @param address Bluetooth address as string
- * @return true if the 2 Least Significant Bits of the address equals 0b11.
+ * @return true if the 2 Most Significant Bits of the address equals 0xC0.
*
* @hide
*/
public static boolean isAddressRandomStatic(@NonNull String address) {
requireNonNull(address);
return checkBluetoothAddress(address)
- && (Integer.parseInt(address.split(":")[5], 16) & 0b11) == 0b11;
+ && (Integer.parseInt(address.split(":")[0], 16) & 0xC0) == 0xC0;
}
/** {@hide} */
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 2ed00b5..d4fa2d5 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3699,6 +3699,17 @@
public static final String FEATURE_KEYSTORE_APP_ATTEST_KEY =
"android.hardware.keystore.app_attest_key";
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
+ * is opted-in to receive per-app compatibility overrides that are applied in
+ * {@link com.android.server.compat.overrides.AppCompatOverridesService}.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_APP_COMPAT_OVERRIDES =
+ "android.software.app_compat_overrides";
+
/** @hide */
public static final boolean APP_ENUMERATION_ENABLED_BY_DEFAULT = true;
diff --git a/core/java/android/hardware/ISensorPrivacyManager.aidl b/core/java/android/hardware/ISensorPrivacyManager.aidl
index debc074..d69a9e1 100644
--- a/core/java/android/hardware/ISensorPrivacyManager.aidl
+++ b/core/java/android/hardware/ISensorPrivacyManager.aidl
@@ -48,4 +48,8 @@
void suppressIndividualSensorPrivacyReminders(int userId, int sensor, IBinder token,
boolean suppress);
+
+ void addUserGlobalIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);
+
+ void removeUserGlobalIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);
}
\ No newline at end of file
diff --git a/core/java/android/hardware/SensorPrivacyManager.java b/core/java/android/hardware/SensorPrivacyManager.java
index b7d95e7..4526ab77 100644
--- a/core/java/android/hardware/SensorPrivacyManager.java
+++ b/core/java/android/hardware/SensorPrivacyManager.java
@@ -24,6 +24,7 @@
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
+import android.app.ActivityManager;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
@@ -247,8 +248,7 @@
@RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
public void addSensorPrivacyListener(@Sensors.Sensor int sensor,
@NonNull OnSensorPrivacyChangedListener listener) {
- addSensorPrivacyListener(sensor, mContext.getUserId(), mContext.getMainExecutor(),
- listener);
+ addSensorPrivacyListener(sensor, mContext.getMainExecutor(), listener);
}
/**
@@ -283,7 +283,25 @@
@RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @NonNull Executor executor,
@NonNull OnSensorPrivacyChangedListener listener) {
- addSensorPrivacyListener(sensor, mContext.getUserId(), executor, listener);
+ Pair<OnSensorPrivacyChangedListener, Integer> key = new Pair<>(listener, sensor);
+ synchronized (mIndividualListeners) {
+ ISensorPrivacyListener iListener = mIndividualListeners.get(key);
+ if (iListener == null) {
+ iListener = new ISensorPrivacyListener.Stub() {
+ @Override
+ public void onSensorPrivacyChanged(boolean enabled) {
+ executor.execute(() -> listener.onSensorPrivacyChanged(sensor, enabled));
+ }
+ };
+ mIndividualListeners.put(key, iListener);
+ }
+
+ try {
+ mService.addUserGlobalIndividualSensorPrivacyListener(sensor, iListener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
/**
@@ -361,7 +379,7 @@
@SystemApi
@RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
public boolean isSensorPrivacyEnabled(@Sensors.Sensor int sensor) {
- return isSensorPrivacyEnabled(sensor, mContext.getUserId());
+ return isSensorPrivacyEnabled(sensor, getCurrentUserId());
}
/**
@@ -392,7 +410,7 @@
@RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY)
public void setSensorPrivacy(@Sources.Source int source, @Sensors.Sensor int sensor,
boolean enable) {
- setSensorPrivacy(source, sensor, enable, mContext.getUserId());
+ setSensorPrivacy(source, sensor, enable, getCurrentUserId());
}
/**
@@ -428,7 +446,7 @@
@RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY)
public void setSensorPrivacyForProfileGroup(@Sources.Source int source,
@Sensors.Sensor int sensor, boolean enable) {
- setSensorPrivacyForProfileGroup(source , sensor, enable, mContext.getUserId());
+ setSensorPrivacyForProfileGroup(source , sensor, enable, getCurrentUserId());
}
/**
@@ -463,7 +481,7 @@
@RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY)
public void suppressSensorPrivacyReminders(int sensor,
boolean suppress) {
- suppressSensorPrivacyReminders(sensor, suppress, mContext.getUserId());
+ suppressSensorPrivacyReminders(sensor, suppress, getCurrentUserId());
}
/**
@@ -590,4 +608,13 @@
throw e.rethrowFromSystemServer();
}
}
+
+ private int getCurrentUserId() {
+ try {
+ return ActivityManager.getService().getCurrentUserId();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return 0;
+ }
}
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index c2a2c4c..3c3ba59 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -169,31 +169,6 @@
}
/**
- * Request authentication of a crypto object. This call operates the face recognition hardware
- * and starts capturing images. It terminates when
- * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
- * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at
- * which point the object is no longer valid. The operation can be canceled by using the
- * provided cancel object.
- *
- * @param crypto object associated with the call or null if none required.
- * @param cancel an object that can be used to cancel authentication
- * @param callback an object to receive authentication events
- * @param handler an optional handler to handle callback events
- * @throws IllegalArgumentException if the crypto operation is not supported or is not backed
- * by
- * <a href="{@docRoot}training/articles/keystore.html">Android
- * Keystore facility</a>.
- * @throws IllegalStateException if the crypto primitive is not initialized.
- * @hide
- */
- @RequiresPermission(USE_BIOMETRIC_INTERNAL)
- public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
- @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
- authenticate(crypto, cancel, callback, handler, mContext.getUserId());
- }
-
- /**
* Use the provided handler thread for events.
*/
private void useHandler(Handler handler) {
@@ -224,8 +199,10 @@
* @throws IllegalStateException if the crypto primitive is not initialized.
* @hide
*/
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
- @NonNull AuthenticationCallback callback, @Nullable Handler handler, int userId) {
+ @NonNull AuthenticationCallback callback, @Nullable Handler handler, int userId,
+ boolean isKeyguardBypassEnabled) {
if (callback == null) {
throw new IllegalArgumentException("Must supply an authentication callback");
}
@@ -247,7 +224,7 @@
final long operationId = crypto != null ? crypto.getOpId() : 0;
Trace.beginSection("FaceManager#authenticate");
mService.authenticate(mToken, operationId, userId, mServiceReceiver,
- mContext.getOpPackageName());
+ mContext.getOpPackageName(), isKeyguardBypassEnabled);
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception while authenticating: ", e);
if (callback != null) {
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index b9a49c6..db02a0ef 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -46,7 +46,7 @@
// Authenticate the given sessionId with a face
void authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver,
- String opPackageName);
+ String opPackageName, boolean isKeyguardBypassEnabled);
// Uses the face hardware to detect for the presence of a face, without giving details
// about accept/reject/lockout.
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 308e6d5..0257408 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -693,6 +693,9 @@
* <p>
* {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
* monitor_storage}
+ * <p>
+ * Note that alternatives such as {@link Context#getExternalFilesDir(String)} or
+ * {@link MediaStore} offer better performance.
*
* @see #getExternalStorageState()
* @see #isExternalStorageRemovable()
@@ -993,6 +996,9 @@
* </p>
* {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
* public_picture}
+ * <p>
+ * Note that alternatives such as {@link Context#getExternalFilesDir(String)} or
+ * {@link MediaStore} offer better performance.
*
* @param type The type of storage directory to return. Should be one of
* {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS},
diff --git a/core/java/android/os/PerformanceHintManager.java b/core/java/android/os/PerformanceHintManager.java
index 6791844..a75b5ef 100644
--- a/core/java/android/os/PerformanceHintManager.java
+++ b/core/java/android/os/PerformanceHintManager.java
@@ -24,24 +24,23 @@
import com.android.internal.util.Preconditions;
import java.io.Closeable;
-import java.util.ArrayList;
/** The PerformanceHintManager allows apps to send performance hint to system. */
@SystemService(Context.PERFORMANCE_HINT_SERVICE)
public final class PerformanceHintManager {
- private static final String TAG = "PerformanceHintManager";
- private final IHintManager mService;
- // HAL preferred update rate
- private final long mPreferredRate;
+ private final long mNativeManagerPtr;
/** @hide */
- public PerformanceHintManager(IHintManager service) {
- mService = service;
- try {
- mPreferredRate = mService.getHintSessionPreferredRate();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ public static PerformanceHintManager create() throws ServiceManager.ServiceNotFoundException {
+ long nativeManagerPtr = nativeAcquireManager();
+ if (nativeManagerPtr == 0) {
+ throw new ServiceManager.ServiceNotFoundException(Context.PERFORMANCE_HINT_SERVICE);
}
+ return new PerformanceHintManager(nativeManagerPtr);
+ }
+
+ private PerformanceHintManager(long nativeManagerPtr) {
+ mNativeManagerPtr = nativeManagerPtr;
}
/**
@@ -57,16 +56,13 @@
*/
@Nullable
public Session createHintSession(@NonNull int[] tids, long initialTargetWorkDurationNanos) {
- try {
- IBinder token = new Binder();
- IHintSession session = mService.createHintSession(token, tids,
- initialTargetWorkDurationNanos);
- if (session == null) return null;
- return new Session(session, sNanoClock, mPreferredRate,
- initialTargetWorkDurationNanos);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ Preconditions.checkNotNull(tids, "tids cannot be null");
+ Preconditions.checkArgumentPositive(initialTargetWorkDurationNanos,
+ "the hint target duration should be positive.");
+ long nativeSessionPtr = nativeCreateSession(mNativeManagerPtr, tids,
+ initialTargetWorkDurationNanos);
+ if (nativeSessionPtr == 0) return null;
+ return new Session(nativeSessionPtr);
}
/**
@@ -75,7 +71,7 @@
* @return the preferred update rate supported by device software.
*/
public long getPreferredUpdateRateNanos() {
- return mPreferredRate;
+ return nativeGetPreferredUpdateRateNanos(mNativeManagerPtr);
}
/**
@@ -101,28 +97,21 @@
* <p>All timings should be in {@link SystemClock#elapsedRealtimeNanos()}.</p>
*/
public static class Session implements Closeable {
- private final IHintSession mSession;
- private final NanoClock mElapsedRealtimeClock;
- // Target duration for choosing update rate
- private long mTargetDurationInNanos;
- // HAL preferred update rate
- private long mPreferredRate;
- // Last update timestamp
- private long mLastUpdateTimeStamp = -1L;
- // Cached samples
- private final ArrayList<Long> mActualDurationNanos;
- private final ArrayList<Long> mTimeStampNanos;
+ private long mNativeSessionPtr;
/** @hide */
- public Session(IHintSession session, NanoClock elapsedRealtimeClock, long preferredRate,
- long durationNanos) {
- mSession = session;
- mElapsedRealtimeClock = elapsedRealtimeClock;
- mTargetDurationInNanos = durationNanos;
- mPreferredRate = preferredRate;
- mActualDurationNanos = new ArrayList<Long>();
- mTimeStampNanos = new ArrayList<Long>();
- mLastUpdateTimeStamp = mElapsedRealtimeClock.nanos();
+ public Session(long nativeSessionPtr) {
+ mNativeSessionPtr = nativeSessionPtr;
+ }
+
+ /** @hide */
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
}
/**
@@ -133,19 +122,7 @@
public void updateTargetWorkDuration(long targetDurationNanos) {
Preconditions.checkArgumentPositive(targetDurationNanos, "the hint target duration"
+ " should be positive.");
- try {
- mSession.updateTargetWorkDuration(targetDurationNanos);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- mTargetDurationInNanos = targetDurationNanos;
- /**
- * Most of the workload is target_duration dependent, so now clear the cached samples
- * as they are most likely obsolete.
- */
- mActualDurationNanos.clear();
- mTimeStampNanos.clear();
- mLastUpdateTimeStamp = mElapsedRealtimeClock.nanos();
+ nativeUpdateTargetWorkDuration(mNativeSessionPtr, targetDurationNanos);
}
/**
@@ -161,38 +138,7 @@
public void reportActualWorkDuration(long actualDurationNanos) {
Preconditions.checkArgumentPositive(actualDurationNanos, "the actual duration should"
+ " be positive.");
- final long now = mElapsedRealtimeClock.nanos();
- mActualDurationNanos.add(actualDurationNanos);
- mTimeStampNanos.add(now);
-
- /**
- * Use current sample to determine the rate limit. We can pick a shorter rate limit
- * if any sample underperformed, however, it could be the lower level system is slow
- * to react. So here we explicitly choose the rate limit with the latest sample.
- */
- long rateLimit =
- actualDurationNanos > mTargetDurationInNanos ? mPreferredRate
- : 10 * mPreferredRate;
-
- if (now - mLastUpdateTimeStamp <= rateLimit) {
- return;
- }
- Preconditions.checkState(mActualDurationNanos.size() == mTimeStampNanos.size());
- final int size = mActualDurationNanos.size();
- long[] actualDurationArray = new long[size];
- long[] timeStampArray = new long[size];
- for (int i = 0; i < size; i++) {
- actualDurationArray[i] = mActualDurationNanos.get(i);
- timeStampArray[i] = mTimeStampNanos.get(i);
- }
- try {
- mSession.reportActualWorkDuration(actualDurationArray, timeStampArray);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- mActualDurationNanos.clear();
- mTimeStampNanos.clear();
- mLastUpdateTimeStamp = now;
+ nativeReportActualWorkDuration(mNativeSessionPtr, actualDurationNanos);
}
/**
@@ -201,26 +147,20 @@
* <p>Once called, you should not call anything else on this object.</p>
*/
public void close() {
- try {
- mSession.close();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ if (mNativeSessionPtr != 0) {
+ nativeCloseSession(mNativeSessionPtr);
+ mNativeSessionPtr = 0;
}
}
}
- /**
- * The interface is to make the FakeClock for testing.
- * @hide
- */
- public interface NanoClock {
- /** Gets the current nanosecond instant of the clock. */
- long nanos();
- }
-
- private static final NanoClock sNanoClock = new NanoClock() {
- public long nanos() {
- return SystemClock.elapsedRealtimeNanos();
- }
- };
+ private static native long nativeAcquireManager();
+ private static native long nativeGetPreferredUpdateRateNanos(long nativeManagerPtr);
+ private static native long nativeCreateSession(long nativeManagerPtr,
+ int[] tids, long initialTargetWorkDurationNanos);
+ private static native void nativeUpdateTargetWorkDuration(long nativeSessionPtr,
+ long targetDurationNanos);
+ private static native void nativeReportActualWorkDuration(long nativeSessionPtr,
+ long actualDurationNanos);
+ private static native void nativeCloseSession(long nativeSessionPtr);
}
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index c8cbc51..ddb6533 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -102,8 +102,6 @@
/** @hide */
public static final long TRACE_TAG_RRO = 1L << 26;
/** @hide */
- public static final long TRACE_TAG_SYSPROP = 1L << 27;
- /** @hide */
public static final long TRACE_TAG_APEX_MANAGER = 1L << 18;
private static final long TRACE_TAG_NOT_READY = 1L << 63;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ac520e8..589ecc0 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9964,15 +9964,18 @@
/**
* Controls the accessibility button mode. System will force-set the value to {@link
- * #ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU} if {@link #NAVIGATION_MODE} is fully
- * gestural.
+ * #ACCESSIBILITY_BUTTON_MODE_GESTURE} if {@link #NAVIGATION_MODE} is button; force-set the
+ * value to {@link ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR} if {@link #NAVIGATION_MODE} is
+ * gestural; otherwise, remain the option.
* <ul>
* <li> 0 = button in navigation bar </li>
* <li> 1 = button floating on the display </li>
+ * <li> 2 = button using gesture to trigger </li>
* </ul>
*
* @see #ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR
* @see #ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU
+ * @see #ACCESSIBILITY_BUTTON_MODE_GESTURE
* @hide
*/
public static final String ACCESSIBILITY_BUTTON_MODE =
@@ -9995,6 +9998,14 @@
public static final int ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU = 0x1;
/**
+ * Accessibility button mode value that specifying the accessibility service or feature to
+ * be toggled via the gesture.
+ *
+ * @hide
+ */
+ public static final int ACCESSIBILITY_BUTTON_MODE_GESTURE = 0x2;
+
+ /**
* The size of the accessibility floating menu.
* <ul>
* <li> 0 = small size
diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java
index a435239..e3bb589 100644
--- a/core/java/android/service/voice/HotwordDetectionService.java
+++ b/core/java/android/service/voice/HotwordDetectionService.java
@@ -72,8 +72,7 @@
@SystemApi
public abstract class HotwordDetectionService extends Service {
private static final String TAG = "HotwordDetectionService";
- // TODO (b/177502877): Set the Debug flag to false before shipping.
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final long UPDATE_TIMEOUT_MILLIS = 5000;
@@ -151,9 +150,7 @@
@Override
public void updateState(PersistableBundle options, SharedMemory sharedMemory,
IRemoteCallback callback) throws RemoteException {
- if (DBG) {
- Log.d(TAG, "#updateState");
- }
+ Log.v(TAG, "#updateState" + (callback != null ? " with callback" : ""));
HotwordDetectionService.this.onUpdateStateInternal(
options,
sharedMemory,
diff --git a/core/java/android/service/voice/SoftwareHotwordDetector.java b/core/java/android/service/voice/SoftwareHotwordDetector.java
index fb540b1..02294e5 100644
--- a/core/java/android/service/voice/SoftwareHotwordDetector.java
+++ b/core/java/android/service/voice/SoftwareHotwordDetector.java
@@ -47,7 +47,7 @@
**/
class SoftwareHotwordDetector extends AbstractHotwordDetector {
private static final String TAG = SoftwareHotwordDetector.class.getSimpleName();
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private final IVoiceInteractionManagerService mManagerService;
private final HotwordDetector.Callback mCallback;
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index fe1fcfc..1111c28 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -73,6 +73,7 @@
import android.view.InputEventReceiver;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.MotionEvent;
import android.view.PixelCopy;
import android.view.Surface;
@@ -224,10 +225,9 @@
final ClientWindowFrames mWinFrames = new ClientWindowFrames();
final Rect mDispatchedContentInsets = new Rect();
final Rect mDispatchedStableInsets = new Rect();
- final Rect mFinalSystemInsets = new Rect();
- final Rect mFinalStableInsets = new Rect();
DisplayCutout mDispatchedDisplayCutout = DisplayCutout.NO_CUTOUT;
final InsetsState mInsetsState = new InsetsState();
+ final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0];
final MergedConfiguration mMergedConfiguration = new MergedConfiguration();
private final Point mSurfaceSize = new Point();
@@ -995,8 +995,8 @@
InputChannel inputChannel = new InputChannel();
if (mSession.addToDisplay(mWindow, mLayout, View.VISIBLE,
- mDisplay.getDisplayId(), mInsetsState, inputChannel, mInsetsState,
- mTempControls) < 0) {
+ mDisplay.getDisplayId(), mRequestedVisibilities, inputChannel,
+ mInsetsState, mTempControls) < 0) {
Log.w(TAG, "Failed to add window while updating wallpaper surface.");
return;
}
@@ -1033,6 +1033,9 @@
.build();
updateSurfaceDimming();
}
+ // Propagate transform hint from WM so we can use the right hint for the
+ // first frame.
+ mBbqSurfaceControl.setTransformHint(mSurfaceControl.getTransformHint());
Surface blastSurface = getOrCreateBLASTSurface(mSurfaceSize.x,
mSurfaceSize.y, mFormat);
// If blastSurface == null that means it hasn't changed since the last
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index e1a4402..0257e55 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -31,6 +31,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Path;
@@ -873,18 +874,147 @@
}
/**
+ * Gets the index of the given display unique id in {@link R.array#config_displayUniqueIdArray}
+ * which is used to get the related cutout configs for that display.
+ *
+ * For multi-display device, {@link R.array#config_displayUniqueIdArray} should be set for each
+ * display if there are different type of cutouts on each display.
+ * For single display device, {@link R.array#config_displayUniqueIdArray} should not to be set
+ * and the system will load the default configs for main built-in display.
+ */
+ private static int getDisplayCutoutConfigIndex(Resources res, String displayUniqueId) {
+ int index = -1;
+ if (displayUniqueId == null || displayUniqueId.isEmpty()) {
+ return index;
+ }
+ final String[] ids = res.getStringArray(R.array.config_displayUniqueIdArray);
+ final int size = ids.length;
+ for (int i = 0; i < size; i++) {
+ if (displayUniqueId.equals(ids[i])) {
+ index = i;
+ break;
+ }
+ }
+ return index;
+ }
+
+ /**
+ * Gets the display cutout by the given display unique id.
+ *
+ * Loads the default config {@link R.string#config_mainBuiltInDisplayCutout) if
+ * {@link R.array#config_displayUniqueIdArray} is not set.
+ */
+ private static String getDisplayCutoutPath(Resources res, String displayUniqueId) {
+ final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+ final String[] array = res.getStringArray(R.array.config_displayCutoutPathArray);
+ if (index >= 0 && index < array.length) {
+ return array[index];
+ }
+ return res.getString(R.string.config_mainBuiltInDisplayCutout);
+ }
+
+ /**
+ * Gets the display cutout approximation rect by the given display unique id.
+ *
+ * Loads the default config {@link R.string#config_mainBuiltInDisplayCutoutRectApproximation} if
+ * {@link R.array#config_displayUniqueIdArray} is not set.
+ */
+ private static String getDisplayCutoutApproximationRect(Resources res, String displayUniqueId) {
+ final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+ final String[] array = res.getStringArray(
+ R.array.config_displayCutoutApproximationRectArray);
+ if (index >= 0 && index < array.length) {
+ return array[index];
+ }
+ return res.getString(R.string.config_mainBuiltInDisplayCutoutRectApproximation);
+ }
+
+ /**
+ * Gets whether to mask a built-in display cutout of a display which is determined by the
+ * given display unique id.
+ *
+ * Loads the default config {@link R.bool#config_maskMainBuiltInDisplayCutout} if
+ * {@link R.array#config_displayUniqueIdArray} is not set.
+ *
+ * @hide
+ */
+ public static boolean getMaskBuiltInDisplayCutout(Resources res, String displayUniqueId) {
+ final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+ final TypedArray array = res.obtainTypedArray(R.array.config_maskBuiltInDisplayCutoutArray);
+ boolean maskCutout;
+ if (index >= 0 && index < array.length()) {
+ maskCutout = array.getBoolean(index, false);
+ } else {
+ maskCutout = res.getBoolean(R.bool.config_maskMainBuiltInDisplayCutout);
+ }
+ array.recycle();
+ return maskCutout;
+ }
+
+ /**
+ * Gets whether to fill a built-in display cutout of a display which is determined by the
+ * given display unique id.
+ *
+ * Loads the default config{@link R.bool#config_fillMainBuiltInDisplayCutout} if
+ * {@link R.array#config_displayUniqueIdArray} is not set.
+ *
+ * @hide
+ */
+ public static boolean getFillBuiltInDisplayCutout(Resources res, String displayUniqueId) {
+ final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+ final TypedArray array = res.obtainTypedArray(R.array.config_fillBuiltInDisplayCutoutArray);
+ boolean fillCutout;
+ if (index >= 0 && index < array.length()) {
+ fillCutout = array.getBoolean(index, false);
+ } else {
+ fillCutout = res.getBoolean(R.bool.config_fillMainBuiltInDisplayCutout);
+ }
+ array.recycle();
+ return fillCutout;
+ }
+
+ /**
+ * Gets the waterfall cutout by the given display unique id.
+ *
+ * Loads the default waterfall dimens if {@link R.array#config_displayUniqueIdArray} is not set.
+ * {@link R.dimen#waterfall_display_left_edge_size},
+ * {@link R.dimen#waterfall_display_top_edge_size},
+ * {@link R.dimen#waterfall_display_right_edge_size},
+ * {@link R.dimen#waterfall_display_bottom_edge_size}
+ */
+ private static Insets getWaterfallInsets(Resources res, String displayUniqueId) {
+ Insets insets;
+ final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+ final TypedArray array = res.obtainTypedArray(R.array.config_waterfallCutoutArray);
+ if (index >= 0 && index < array.length() && array.getResourceId(index, 0) > 0) {
+ final int resourceId = array.getResourceId(index, 0);
+ final TypedArray waterfall = res.obtainTypedArray(resourceId);
+ insets = Insets.of(
+ waterfall.getDimensionPixelSize(0 /* waterfall left edge size */, 0),
+ waterfall.getDimensionPixelSize(1 /* waterfall top edge size */, 0),
+ waterfall.getDimensionPixelSize(2 /* waterfall right edge size */, 0),
+ waterfall.getDimensionPixelSize(3 /* waterfall bottom edge size */, 0));
+ waterfall.recycle();
+ } else {
+ insets = loadWaterfallInset(res);
+ }
+ array.recycle();
+ return insets;
+ }
+
+ /**
* Creates the display cutout according to
* @android:string/config_mainBuiltInDisplayCutoutRectApproximation, which is the closest
* rectangle-base approximation of the cutout.
*
* @hide
*/
- public static DisplayCutout fromResourcesRectApproximation(Resources res, int displayWidth,
- int displayHeight) {
- return pathAndDisplayCutoutFromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout),
- res.getString(R.string.config_mainBuiltInDisplayCutoutRectApproximation),
+ public static DisplayCutout fromResourcesRectApproximation(Resources res,
+ String displayUniqueId, int displayWidth, int displayHeight) {
+ return pathAndDisplayCutoutFromSpec(getDisplayCutoutPath(res, displayUniqueId),
+ getDisplayCutoutApproximationRect(res, displayUniqueId),
displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT,
- loadWaterfallInset(res)).second;
+ getWaterfallInsets(res, displayUniqueId)).second;
}
/**
@@ -892,11 +1022,11 @@
*
* @hide
*/
- public static Path pathFromResources(Resources res, int displayWidth, int displayHeight) {
- return pathAndDisplayCutoutFromSpec(
- res.getString(R.string.config_mainBuiltInDisplayCutout), null,
+ public static Path pathFromResources(Resources res, String displayUniqueId, int displayWidth,
+ int displayHeight) {
+ return pathAndDisplayCutoutFromSpec(getDisplayCutoutPath(res, displayUniqueId), null,
displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT,
- loadWaterfallInset(res)).first;
+ getWaterfallInsets(res, displayUniqueId)).first;
}
/**
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index f4539c2..9ce4122 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -53,6 +53,7 @@
import android.view.KeyEvent;
import android.view.InputEvent;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.MagnificationSpec;
import android.view.MotionEvent;
import android.view.InputChannel;
@@ -720,14 +721,15 @@
int displayId, in IDisplayWindowInsetsController displayWindowInsetsController);
/**
- * Called when a remote process modifies insets on a display window container.
+ * Called when a remote process updates the requested visibilities of insets on a display window
+ * container.
*/
- void modifyDisplayWindowInsets(int displayId, in InsetsState state);
+ void updateDisplayWindowRequestedVisibilities(int displayId, in InsetsVisibilities vis);
/**
* Called to get the expected window insets.
*
- * @return {@code true} if system bars are always comsumed.
+ * @return {@code true} if system bars are always consumed.
*/
boolean getWindowInsets(in WindowManager.LayoutParams attrs, int displayId,
out InsetsState outInsetsState);
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 7bad5cb..a6abed0 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -32,6 +32,7 @@
import android.view.WindowManager;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
@@ -46,12 +47,12 @@
*/
interface IWindowSession {
int addToDisplay(IWindow window, in WindowManager.LayoutParams attrs,
- in int viewVisibility, in int layerStackId, in InsetsState requestedVisibility,
+ in int viewVisibility, in int layerStackId, in InsetsVisibilities requestedVisibilities,
out InputChannel outInputChannel, out InsetsState insetsState,
out InsetsSourceControl[] activeControls);
int addToDisplayAsUser(IWindow window, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, in int userId,
- in InsetsState requestedVisibility, out InputChannel outInputChannel,
+ in InsetsVisibilities requestedVisibilities, out InputChannel outInputChannel,
out InsetsState insetsState, out InsetsSourceControl[] activeControls);
int addToDisplayWithoutInputChannel(IWindow window, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, out InsetsState insetsState);
@@ -285,10 +286,9 @@
oneway void updateTapExcludeRegion(IWindow window, in Region region);
/**
- * Called when the client has changed the local insets state, and now the server should reflect
- * that new state.
+ * Updates the requested visibilities of insets.
*/
- oneway void insetsModified(IWindow window, in InsetsState state);
+ oneway void updateRequestedVisibilities(IWindow window, in InsetsVisibilities visibilities);
/**
* Called when the system gesture exclusion has changed.
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 6f915c9..acdaa52 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -107,9 +107,12 @@
boolean hasControl);
/**
- * Called when insets have been modified by the client and should be reported back to WM.
+ * Called when the requested visibilities of insets have been modified by the client.
+ * The visibilities should be reported back to WM.
+ *
+ * @param visibilities A collection of the requested visibilities.
*/
- void onInsetsModified(InsetsState insetsState);
+ void updateRequestedVisibilities(InsetsVisibilities visibilities);
/**
* @return Whether the host has any callbacks it wants to synchronize the animations with.
@@ -536,10 +539,8 @@
/** The state dispatched from server */
private final InsetsState mLastDispatchedState = new InsetsState();
- // TODO: Use other class to represent the requested visibility of each type, because the
- // display frame and the frame in each source are not used.
/** The requested visibilities sent to server */
- private final InsetsState mRequestedState = new InsetsState();
+ private final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
private final Rect mFrame = new Rect();
private final BiFunction<InsetsController, Integer, InsetsSourceConsumer> mConsumerCreator;
@@ -801,7 +802,7 @@
}
}
- boolean requestedStateStale = false;
+ boolean requestedVisibilityStale = false;
final int[] showTypes = new int[1];
final int[] hideTypes = new int[1];
@@ -822,20 +823,20 @@
final InsetsSourceConsumer consumer = getSourceConsumer(type);
consumer.setControl(control, showTypes, hideTypes);
- if (!requestedStateStale) {
+ if (!requestedVisibilityStale) {
final boolean requestedVisible = consumer.isRequestedVisible();
// We might have changed our requested visibilities while we don't have the control,
// so we need to update our requested state once we have control. Otherwise, our
// requested state at the server side might be incorrect.
final boolean requestedVisibilityChanged =
- requestedVisible != mRequestedState.getSourceOrDefaultVisibility(type);
+ requestedVisible != mRequestedVisibilities.getVisibility(type);
// The IME client visibility will be reset by insets source provider while updating
// control, so if IME is requested visible, we need to send the request to server.
final boolean imeRequestedVisible = type == ITYPE_IME && requestedVisible;
- requestedStateStale = requestedVisibilityChanged || imeRequestedVisible;
+ requestedVisibilityStale = requestedVisibilityChanged || imeRequestedVisible;
}
}
@@ -861,7 +862,7 @@
}
// InsetsSourceConsumer#setControl might change the requested visibility.
- updateRequestedVisibility();
+ updateRequestedVisibilities();
}
@Override
@@ -1015,7 +1016,7 @@
if (types == 0) {
// nothing to animate.
listener.onCancelled(null);
- updateRequestedVisibility();
+ updateRequestedVisibilities();
if (DEBUG) Log.d(TAG, "no types to animate in controlAnimationUnchecked");
return;
}
@@ -1051,7 +1052,7 @@
}
});
}
- updateRequestedVisibility();
+ updateRequestedVisibilities();
Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromApi", 0);
return;
}
@@ -1059,7 +1060,7 @@
if (typesReady == 0) {
if (DEBUG) Log.d(TAG, "No types ready. onCancelled()");
listener.onCancelled(null);
- updateRequestedVisibility();
+ updateRequestedVisibilities();
return;
}
@@ -1091,7 +1092,7 @@
} else {
hideDirectly(types, false /* animationFinished */, animationType, fromIme);
}
- updateRequestedVisibility();
+ updateRequestedVisibilities();
}
/**
@@ -1348,7 +1349,7 @@
/**
* Sends the requested visibilities to window manager if any of them is changed.
*/
- private void updateRequestedVisibility() {
+ private void updateRequestedVisibilities() {
boolean changed = false;
for (int i = mRequestedVisibilityChanged.size() - 1; i >= 0; i--) {
final InsetsSourceConsumer consumer = mRequestedVisibilityChanged.valueAt(i);
@@ -1357,8 +1358,8 @@
continue;
}
final boolean requestedVisible = consumer.isRequestedVisible();
- if (requestedVisible != mRequestedState.getSourceOrDefaultVisibility(type)) {
- mRequestedState.getSource(type).setVisible(requestedVisible);
+ if (mRequestedVisibilities.getVisibility(type) != requestedVisible) {
+ mRequestedVisibilities.setVisibility(type, requestedVisible);
changed = true;
}
}
@@ -1366,11 +1367,11 @@
if (!changed) {
return;
}
- mHost.onInsetsModified(mRequestedState);
+ mHost.updateRequestedVisibilities(mRequestedVisibilities);
}
- InsetsState getRequestedVisibility() {
- return mRequestedState;
+ InsetsVisibilities getRequestedVisibilities() {
+ return mRequestedVisibilities;
}
@VisibleForTesting
@@ -1425,7 +1426,7 @@
for (int i = internalTypes.size() - 1; i >= 0; i--) {
getSourceConsumer(internalTypes.valueAt(i)).hide(animationFinished, animationType);
}
- updateRequestedVisibility();
+ updateRequestedVisibilities();
if (fromIme) {
Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.hideRequestFromIme", 0);
@@ -1441,7 +1442,7 @@
for (int i = internalTypes.size() - 1; i >= 0; i--) {
getSourceConsumer(internalTypes.valueAt(i)).show(false /* fromIme */);
}
- updateRequestedVisibility();
+ updateRequestedVisibilities();
if (fromIme) {
Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromIme", 0);
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 37101b7..f4444a1 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -878,16 +878,5 @@
+ ", mSources= { " + joiner
+ " }";
}
-
- public @NonNull String toSourceVisibilityString() {
- StringJoiner joiner = new StringJoiner(", ");
- for (int i = 0; i < SIZE; i++) {
- InsetsSource source = mSources[i];
- if (source != null) {
- joiner.add(typeToString(i) + ": " + (source.isVisible() ? "visible" : "invisible"));
- }
- }
- return joiner.toString();
- }
}
diff --git a/core/java/android/view/InsetsVisibilities.aidl b/core/java/android/view/InsetsVisibilities.aidl
new file mode 100644
index 0000000..bd573ea
--- /dev/null
+++ b/core/java/android/view/InsetsVisibilities.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+parcelable InsetsVisibilities;
diff --git a/core/java/android/view/InsetsVisibilities.java b/core/java/android/view/InsetsVisibilities.java
new file mode 100644
index 0000000..30668ba
--- /dev/null
+++ b/core/java/android/view/InsetsVisibilities.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+import java.util.StringJoiner;
+
+/**
+ * A collection of visibilities of insets. This is used for carrying the requested visibilities.
+ * @hide
+ */
+public class InsetsVisibilities implements Parcelable {
+
+ private static final int UNSPECIFIED = 0;
+ private static final int VISIBLE = 1;
+ private static final int INVISIBLE = -1;
+
+ private final int[] mVisibilities = new int[InsetsState.SIZE];
+
+ public InsetsVisibilities() {
+ }
+
+ public InsetsVisibilities(InsetsVisibilities other) {
+ set(other);
+ }
+
+ public InsetsVisibilities(Parcel in) {
+ in.readIntArray(mVisibilities);
+ }
+
+ /**
+ * Copies from another {@link InsetsVisibilities}.
+ *
+ * @param other an instance of {@link InsetsVisibilities}.
+ */
+ public void set(InsetsVisibilities other) {
+ System.arraycopy(other.mVisibilities, InsetsState.FIRST_TYPE, mVisibilities,
+ InsetsState.FIRST_TYPE, InsetsState.SIZE);
+ }
+
+ /**
+ * Sets a visibility to a type.
+ *
+ * @param type The {@link @InsetsState.InternalInsetsType}.
+ * @param visible {@code true} represents visible; {@code false} represents invisible.
+ */
+ public void setVisibility(@InsetsState.InternalInsetsType int type, boolean visible) {
+ mVisibilities[type] = visible ? VISIBLE : INVISIBLE;
+ }
+
+ /**
+ * Returns the specified insets visibility of the type. If it has never been specified,
+ * this returns the default visibility.
+ *
+ * @param type The {@link @InsetsState.InternalInsetsType}.
+ * @return The specified visibility or the default one if it is not specified.
+ */
+ public boolean getVisibility(@InsetsState.InternalInsetsType int type) {
+ final int visibility = mVisibilities[type];
+ return visibility == UNSPECIFIED
+ ? InsetsState.getDefaultVisibility(type)
+ : visibility == VISIBLE;
+ }
+
+ @Override
+ public String toString() {
+ StringJoiner joiner = new StringJoiner(", ");
+ for (int type = InsetsState.FIRST_TYPE; type <= InsetsState.LAST_TYPE; type++) {
+ final int visibility = mVisibilities[type];
+ if (visibility != UNSPECIFIED) {
+ joiner.add(InsetsState.typeToString(type) + ": "
+ + (visibility == VISIBLE ? "visible" : "invisible"));
+ }
+ }
+ return joiner.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(mVisibilities);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof InsetsVisibilities)) {
+ return false;
+ }
+ return Arrays.equals(mVisibilities, ((InsetsVisibilities) other).mVisibilities);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeIntArray(mVisibilities);
+ }
+
+ public static final @NonNull Creator<InsetsVisibilities> CREATOR =
+ new Creator<InsetsVisibilities>() {
+
+ public InsetsVisibilities createFromParcel(Parcel in) {
+ return new InsetsVisibilities(in);
+ }
+
+ public InsetsVisibilities[] newArray(int size) {
+ return new InsetsVisibilities[size];
+ }
+ };
+}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index b300f30..d6186d7 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -148,6 +148,8 @@
float width, float height, float vecX, float vecY,
float maxStretchAmountX, float maxStretchAmountY, float childRelativeLeft,
float childRelativeTop, float childRelativeRight, float childRelativeBottom);
+ private static native void nativeSetTrustedOverlay(long transactionObj, long nativeObject,
+ boolean isTrustedOverlay);
private static native boolean nativeClearContentFrameStats(long nativeObject);
private static native boolean nativeGetContentFrameStats(long nativeObject, WindowContentFrameStats outStats);
@@ -3435,6 +3437,17 @@
return this;
}
+ /**
+ * Sets the trusted overlay state on this SurfaceControl and it is inherited to all the
+ * children. The caller must hold the ACCESS_SURFACE_FLINGER permission.
+ * @hide
+ */
+ public Transaction setTrustedOverlay(SurfaceControl sc, boolean isTrustedOverlay) {
+ checkPreconditions(sc);
+ nativeSetTrustedOverlay(mNativeObject, sc.mNativeObject, isTrustedOverlay);
+ 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 cb3eb06..27eb2a5 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1133,7 +1133,7 @@
controlInsetsForCompatibility(mWindowAttributes);
res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId,
- mInsetsController.getRequestedVisibility(), inputChannel, mTempInsets,
+ mInsetsController.getRequestedVisibilities(), inputChannel, mTempInsets,
mTempControls);
if (mTranslator != null) {
mTranslator.translateInsetsStateInScreenToAppWindow(mTempInsets);
@@ -2517,6 +2517,14 @@
|| lp.type == TYPE_VOLUME_OVERLAY;
}
+ private Rect getWindowBoundsInsetSystemBars() {
+ final Rect bounds = new Rect(
+ mContext.getResources().getConfiguration().windowConfiguration.getBounds());
+ bounds.inset(mInsetsController.getState().calculateInsets(
+ bounds, Type.systemBars(), false /* ignoreVisibility */));
+ return bounds;
+ }
+
int dipToPx(int dip) {
final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
return (int) (displayMetrics.density * dip + 0.5f);
@@ -2603,8 +2611,9 @@
|| lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
// For wrap content, we have to remeasure later on anyways. Use size consistent with
// below so we get best use of the measure cache.
- desiredWindowWidth = dipToPx(config.screenWidthDp);
- desiredWindowHeight = dipToPx(config.screenHeightDp);
+ final Rect bounds = getWindowBoundsInsetSystemBars();
+ desiredWindowWidth = bounds.width();
+ desiredWindowHeight = bounds.height();
} else {
// After addToDisplay, the frame contains the frameHint from window manager, which
// for most windows is going to be the same size as the result of relayoutWindow.
@@ -2681,9 +2690,9 @@
desiredWindowWidth = size.x;
desiredWindowHeight = size.y;
} else {
- Configuration config = res.getConfiguration();
- desiredWindowWidth = dipToPx(config.screenWidthDp);
- desiredWindowHeight = dipToPx(config.screenHeightDp);
+ final Rect bounds = getWindowBoundsInsetSystemBars();
+ desiredWindowWidth = bounds.width();
+ desiredWindowHeight = bounds.height();
}
}
}
diff --git a/core/java/android/view/ViewRootInsetsControllerHost.java b/core/java/android/view/ViewRootInsetsControllerHost.java
index ce882da..efffa2b 100644
--- a/core/java/android/view/ViewRootInsetsControllerHost.java
+++ b/core/java/android/view/ViewRootInsetsControllerHost.java
@@ -149,10 +149,10 @@
}
@Override
- public void onInsetsModified(InsetsState insetsState) {
+ public void updateRequestedVisibilities(InsetsVisibilities vis) {
try {
if (mViewRoot.mAdded) {
- mViewRoot.mWindowSession.insetsModified(mViewRoot.mWindow, insetsState);
+ mViewRoot.mWindowSession.updateRequestedVisibilities(mViewRoot.mWindow, vis);
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to call insetsModified", e);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index fcfb0ab..8cc8866 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -400,6 +400,11 @@
*/
int TRANSIT_PIP = 10;
/**
+ * The screen is turning on.
+ * @hide
+ */
+ int TRANSIT_WAKE = 11;
+ /**
* The first slot for custom transition types. Callers (like Shell) can make use of custom
* transition types for dealing with special cases. These types are effectively ignored by
* Core and will just be passed along as part of TransitionInfo objects. An example is
@@ -408,7 +413,7 @@
* implementation.
* @hide
*/
- int TRANSIT_FIRST_CUSTOM = 11;
+ int TRANSIT_FIRST_CUSTOM = 12;
/**
* @hide
@@ -425,6 +430,7 @@
TRANSIT_KEYGUARD_OCCLUDE,
TRANSIT_KEYGUARD_UNOCCLUDE,
TRANSIT_PIP,
+ TRANSIT_WAKE,
TRANSIT_FIRST_CUSTOM
})
@Retention(RetentionPolicy.SOURCE)
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index ae54f51..c413a9b 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -135,7 +135,7 @@
*/
@Override
public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs,
- int viewVisibility, int displayId, InsetsState requestedVisibility,
+ int viewVisibility, int displayId, InsetsVisibilities requestedVisibilities,
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
final SurfaceControl.Builder b = new SurfaceControl.Builder(mSurfaceSession)
@@ -181,10 +181,10 @@
*/
@Override
public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
- int viewVisibility, int displayId, int userId, InsetsState requestedVisibility,
+ int viewVisibility, int displayId, int userId, InsetsVisibilities requestedVisibilities,
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
- return addToDisplay(window, attrs, viewVisibility, displayId, requestedVisibility,
+ return addToDisplay(window, attrs, viewVisibility, displayId, requestedVisibilities,
outInputChannel, outInsetsState, outActiveControls);
}
@@ -454,7 +454,7 @@
}
@Override
- public void insetsModified(android.view.IWindow window, android.view.InsetsState state) {
+ public void updateRequestedVisibilities(IWindow window, InsetsVisibilities visibilities) {
}
@Override
diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java
index 566f154..8c64474 100644
--- a/core/java/android/window/StartingWindowInfo.java
+++ b/core/java/android/window/StartingWindowInfo.java
@@ -22,6 +22,7 @@
import android.annotation.TestApi;
import android.app.ActivityManager;
import android.app.TaskInfo;
+import android.content.pm.ActivityInfo;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.InsetsState;
@@ -78,6 +79,14 @@
public ActivityManager.RunningTaskInfo taskInfo;
/**
+ * The {@link ActivityInfo} of the target activity which to create the starting window.
+ * It can be null if the info is the same as the top in task info.
+ * @hide
+ */
+ @Nullable
+ public ActivityInfo targetActivityInfo;
+
+ /**
* InsetsState of TopFullscreenOpaqueWindow
* @hide
*/
@@ -174,6 +183,7 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeTypedObject(taskInfo, flags);
+ dest.writeTypedObject(targetActivityInfo, flags);
dest.writeInt(startingWindowTypeParameter);
dest.writeTypedObject(topOpaqueWindowInsetsState, flags);
dest.writeTypedObject(topOpaqueWindowLayoutParams, flags);
@@ -185,6 +195,7 @@
void readFromParcel(@NonNull Parcel source) {
taskInfo = source.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
+ targetActivityInfo = source.readTypedObject(ActivityInfo.CREATOR);
startingWindowTypeParameter = source.readInt();
topOpaqueWindowInsetsState = source.readTypedObject(InsetsState.CREATOR);
topOpaqueWindowLayoutParams = source.readTypedObject(
@@ -198,6 +209,7 @@
@Override
public String toString() {
return "StartingWindowInfo{taskId=" + taskInfo.taskId
+ + " targetActivityInfo=" + targetActivityInfo
+ " displayId=" + taskInfo.displayId
+ " topActivityType=" + taskInfo.topActivityType
+ " preferredStartingWindowType="
diff --git a/core/java/android/window/TaskFragmentAppearedInfo.java b/core/java/android/window/TaskFragmentAppearedInfo.java
index 234b30c..89d9a95 100644
--- a/core/java/android/window/TaskFragmentAppearedInfo.java
+++ b/core/java/android/window/TaskFragmentAppearedInfo.java
@@ -17,6 +17,7 @@
package android.window;
import android.annotation.NonNull;
+import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.SurfaceControl;
@@ -25,6 +26,7 @@
* Data object for the TaskFragment info provided when a TaskFragment is presented to an organizer.
* @hide
*/
+@TestApi
public final class TaskFragmentAppearedInfo implements Parcelable {
@NonNull
@@ -33,16 +35,19 @@
@NonNull
private final SurfaceControl mLeash;
+ /** @hide */
public TaskFragmentAppearedInfo(
@NonNull TaskFragmentInfo taskFragmentInfo, @NonNull SurfaceControl leash) {
mTaskFragmentInfo = taskFragmentInfo;
mLeash = leash;
}
+ @NonNull
public TaskFragmentInfo getTaskFragmentInfo() {
return mTaskFragmentInfo;
}
+ @NonNull
public SurfaceControl getLeash() {
return mLeash;
}
@@ -52,6 +57,7 @@
mLeash = in.readTypedObject(SurfaceControl.CREATOR);
}
+ /** @hide */
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeTypedObject(mTaskFragmentInfo, flags);
@@ -79,6 +85,7 @@
+ "}";
}
+ /** @hide */
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/window/TaskFragmentCreationParams.java b/core/java/android/window/TaskFragmentCreationParams.java
index e4d6a6c..81ab783 100644
--- a/core/java/android/window/TaskFragmentCreationParams.java
+++ b/core/java/android/window/TaskFragmentCreationParams.java
@@ -20,6 +20,7 @@
import static android.app.WindowConfiguration.WindowingMode;
import android.annotation.NonNull;
+import android.annotation.TestApi;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.Parcel;
@@ -29,11 +30,12 @@
* Data object for options to create TaskFragment with.
* @hide
*/
+@TestApi
public final class TaskFragmentCreationParams implements Parcelable {
/** The organizer that will organize this TaskFragment. */
@NonNull
- private final ITaskFragmentOrganizer mOrganizer;
+ private final TaskFragmentOrganizerToken mOrganizer;
/**
* Unique token assigned from the client organizer to identify the {@link TaskFragmentInfo} when
@@ -58,25 +60,29 @@
private int mWindowingMode = WINDOWING_MODE_UNDEFINED;
private TaskFragmentCreationParams(
- @NonNull ITaskFragmentOrganizer organizer, @NonNull IBinder fragmentToken,
- @NonNull IBinder ownerToken) {
+ @NonNull TaskFragmentOrganizerToken organizer,
+ @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken) {
mOrganizer = organizer;
mFragmentToken = fragmentToken;
mOwnerToken = ownerToken;
}
- public ITaskFragmentOrganizer getOrganizer() {
+ @NonNull
+ public TaskFragmentOrganizerToken getOrganizer() {
return mOrganizer;
}
+ @NonNull
public IBinder getFragmentToken() {
return mFragmentToken;
}
+ @NonNull
public IBinder getOwnerToken() {
return mOwnerToken;
}
+ @NonNull
public Rect getInitialBounds() {
return mInitialBounds;
}
@@ -87,16 +93,17 @@
}
private TaskFragmentCreationParams(Parcel in) {
- mOrganizer = ITaskFragmentOrganizer.Stub.asInterface(in.readStrongBinder());
+ mOrganizer = TaskFragmentOrganizerToken.CREATOR.createFromParcel(in);
mFragmentToken = in.readStrongBinder();
mOwnerToken = in.readStrongBinder();
mInitialBounds.readFromParcel(in);
mWindowingMode = in.readInt();
}
+ /** @hide */
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeStrongInterface(mOrganizer);
+ mOrganizer.writeToParcel(dest, flags);
dest.writeStrongBinder(mFragmentToken);
dest.writeStrongBinder(mOwnerToken);
mInitialBounds.writeToParcel(dest, flags);
@@ -128,16 +135,17 @@
+ "}";
}
+ /** @hide */
@Override
public int describeContents() {
return 0;
}
/** Builder to construct the options to create TaskFragment with. */
- public static class Builder {
+ public static final class Builder {
@NonNull
- private final ITaskFragmentOrganizer mOrganizer;
+ private final TaskFragmentOrganizerToken mOrganizer;
@NonNull
private final IBinder mFragmentToken;
@@ -151,26 +159,29 @@
@WindowingMode
private int mWindowingMode = WINDOWING_MODE_UNDEFINED;
- public Builder(@NonNull ITaskFragmentOrganizer organizer, @NonNull IBinder fragmentToken,
- @NonNull IBinder ownerToken) {
+ public Builder(@NonNull TaskFragmentOrganizerToken organizer,
+ @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken) {
mOrganizer = organizer;
mFragmentToken = fragmentToken;
mOwnerToken = ownerToken;
}
/** Sets the initial bounds for the TaskFragment. */
+ @NonNull
public Builder setInitialBounds(@NonNull Rect bounds) {
mInitialBounds.set(bounds);
return this;
}
/** Sets the initial windowing mode for the TaskFragment. */
+ @NonNull
public Builder setWindowingMode(@WindowingMode int windowingMode) {
mWindowingMode = windowingMode;
return this;
}
/** Constructs the options to create TaskFragment with. */
+ @NonNull
public TaskFragmentCreationParams build() {
final TaskFragmentCreationParams result = new TaskFragmentCreationParams(
mOrganizer, mFragmentToken, mOwnerToken);
diff --git a/core/java/android/window/TaskFragmentInfo.java b/core/java/android/window/TaskFragmentInfo.java
index 45975db..dac420b 100644
--- a/core/java/android/window/TaskFragmentInfo.java
+++ b/core/java/android/window/TaskFragmentInfo.java
@@ -22,6 +22,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.content.res.Configuration;
import android.graphics.Point;
import android.os.IBinder;
@@ -35,11 +36,12 @@
* Stores information about a particular TaskFragment.
* @hide
*/
+@TestApi
public final class TaskFragmentInfo implements Parcelable {
/**
- * Client assigned unique token in {@link TaskFragmentCreationParams#mFragmentToken} to create
- * this TaskFragment with.
+ * Client assigned unique token in {@link TaskFragmentCreationParams#getFragmentToken()} to
+ * create this TaskFragment with.
*/
@NonNull
private final IBinder mFragmentToken;
@@ -50,9 +52,12 @@
@NonNull
private final Configuration mConfiguration = new Configuration();
- /** Whether the TaskFragment contains any child Activity. */
+ /** Whether the TaskFragment contains any child Window Container. */
private final boolean mIsEmpty;
+ /** Whether the TaskFragment contains any running Activity. */
+ private final boolean mHasRunningActivity;
+
/** Whether this TaskFragment is visible on the window hierarchy. */
private final boolean mIsVisible;
@@ -60,32 +65,38 @@
* List of Activity tokens that are children of this TaskFragment. It only contains Activities
* that belong to the organizer process for security.
*/
+ @NonNull
private final List<IBinder> mActivities = new ArrayList<>();
/** Relative position of the fragment's top left corner in the parent container. */
private final Point mPositionInParent;
+ /** @hide */
public TaskFragmentInfo(
@NonNull IBinder fragmentToken, @NonNull WindowContainerToken token,
- @NonNull Configuration configuration, boolean isEmpty, boolean isVisible,
- List<IBinder> activities, @NonNull Point positionInParent) {
+ @NonNull Configuration configuration, boolean isEmpty, boolean hasRunningActivity,
+ boolean isVisible, @NonNull List<IBinder> activities, @NonNull Point positionInParent) {
mFragmentToken = requireNonNull(fragmentToken);
mToken = requireNonNull(token);
mConfiguration.setTo(configuration);
mIsEmpty = isEmpty;
+ mHasRunningActivity = hasRunningActivity;
mIsVisible = isVisible;
mActivities.addAll(activities);
mPositionInParent = requireNonNull(positionInParent);
}
+ @NonNull
public IBinder getFragmentToken() {
return mFragmentToken;
}
+ @NonNull
public WindowContainerToken getToken() {
return mToken;
}
+ @NonNull
public Configuration getConfiguration() {
return mConfiguration;
}
@@ -94,10 +105,15 @@
return mIsEmpty;
}
+ public boolean hasRunningActivity() {
+ return mHasRunningActivity;
+ }
+
public boolean isVisible() {
return mIsVisible;
}
+ @NonNull
public List<IBinder> getActivities() {
return mActivities;
}
@@ -125,6 +141,7 @@
return mFragmentToken.equals(that.mFragmentToken)
&& mToken.equals(that.mToken)
&& mIsEmpty == that.mIsEmpty
+ && mHasRunningActivity == that.mHasRunningActivity
&& mIsVisible == that.mIsVisible
&& getWindowingMode() == that.getWindowingMode()
&& mActivities.equals(that.mActivities)
@@ -136,17 +153,20 @@
mToken = in.readTypedObject(WindowContainerToken.CREATOR);
mConfiguration.readFromParcel(in);
mIsEmpty = in.readBoolean();
+ mHasRunningActivity = in.readBoolean();
mIsVisible = in.readBoolean();
in.readBinderList(mActivities);
mPositionInParent = requireNonNull(in.readTypedObject(Point.CREATOR));
}
+ /** @hide */
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeStrongBinder(mFragmentToken);
dest.writeTypedObject(mToken, flags);
mConfiguration.writeToParcel(dest, flags);
dest.writeBoolean(mIsEmpty);
+ dest.writeBoolean(mHasRunningActivity);
dest.writeBoolean(mIsVisible);
dest.writeBinderList(mActivities);
dest.writeTypedObject(mPositionInParent, flags);
@@ -172,11 +192,13 @@
+ " fragmentToken=" + mFragmentToken
+ " token=" + mToken
+ " isEmpty=" + mIsEmpty
+ + " hasRunningActivity=" + mHasRunningActivity
+ " isVisible=" + mIsVisible
+ " positionInParent=" + mPositionInParent
+ "}";
}
+ /** @hide */
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java
index b252df7..f22f0b2 100644
--- a/core/java/android/window/TaskFragmentOrganizer.java
+++ b/core/java/android/window/TaskFragmentOrganizer.java
@@ -18,6 +18,7 @@
import android.annotation.CallSuper;
import android.annotation.NonNull;
+import android.annotation.TestApi;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.IBinder;
@@ -26,9 +27,10 @@
import java.util.concurrent.Executor;
/**
- * Interface for WindowManager to delegate control of {@link com.android.server.wm.TaskFragment}.
+ * Interface for WindowManager to delegate control of {@code TaskFragment}.
* @hide
*/
+@TestApi
public class TaskFragmentOrganizer extends WindowOrganizer {
/**
@@ -39,6 +41,7 @@
/**
* Creates a {@link Bundle} with an exception that can be passed to
* {@link ITaskFragmentOrganizer#onTaskFragmentError}.
+ * @hide
*/
public static Bundle putExceptionInBundle(@NonNull Throwable exception) {
final Bundle exceptionBundle = new Bundle();
@@ -126,6 +129,8 @@
super.applyTransaction(t);
}
+ // Suppress the lint because it is not a registration method.
+ @SuppressWarnings("ExecutorRegistration")
@Override
public int applySyncTransaction(@NonNull WindowContainerTransaction t,
@NonNull WindowContainerTransactionCallback callback) {
@@ -169,8 +174,11 @@
}
};
- public ITaskFragmentOrganizer getIOrganizer() {
- return mInterface;
+ private final TaskFragmentOrganizerToken mToken = new TaskFragmentOrganizerToken(mInterface);
+
+ @NonNull
+ public TaskFragmentOrganizerToken getOrganizerToken() {
+ return mToken;
}
private ITaskFragmentOrganizerController getController() {
diff --git a/core/java/android/window/TaskFragmentOrganizerToken.java b/core/java/android/window/TaskFragmentOrganizerToken.java
new file mode 100644
index 0000000..d5216a6
--- /dev/null
+++ b/core/java/android/window/TaskFragmentOrganizerToken.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.TestApi;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Interface to communicate between window manager and {@link TaskFragmentOrganizer}.
+ * <p>
+ * Window manager will dispatch TaskFragment information updates via this interface.
+ * It is necessary because {@link ITaskFragmentOrganizer} aidl interface can not be used as a
+ * {@link TestApi}.
+ * @hide
+ */
+@TestApi
+public final class TaskFragmentOrganizerToken implements Parcelable {
+ private final ITaskFragmentOrganizer mRealToken;
+
+ TaskFragmentOrganizerToken(ITaskFragmentOrganizer realToken) {
+ mRealToken = realToken;
+ }
+
+ /** @hide */
+ public IBinder asBinder() {
+ return mRealToken.asBinder();
+ }
+
+ /** @hide */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeStrongInterface(mRealToken);
+ }
+
+ /** @hide */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull
+ public static final Creator<TaskFragmentOrganizerToken> CREATOR =
+ new Creator<TaskFragmentOrganizerToken>() {
+ @Override
+ public TaskFragmentOrganizerToken createFromParcel(Parcel in) {
+ final ITaskFragmentOrganizer realToken =
+ ITaskFragmentOrganizer.Stub.asInterface(in.readStrongBinder());
+ // The TaskFragmentOrganizerToken may be null for TaskOrganizer or
+ // DisplayAreaOrganizer.
+ if (realToken == null) {
+ return null;
+ }
+ return new TaskFragmentOrganizerToken(realToken);
+ }
+
+ @Override
+ public TaskFragmentOrganizerToken[] newArray(int size) {
+ return new TaskFragmentOrganizerToken[size];
+ }
+ };
+
+ @Override
+ public int hashCode() {
+ return mRealToken.asBinder().hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "TaskFragmentOrganizerToken{" + mRealToken + "}";
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (!(obj instanceof TaskFragmentOrganizerToken)) {
+ return false;
+ }
+ return mRealToken.asBinder() == ((TaskFragmentOrganizerToken) obj).asBinder();
+ }
+}
diff --git a/core/java/android/window/TransitionFilter.java b/core/java/android/window/TransitionFilter.java
index 607e316..bb3f90b 100644
--- a/core/java/android/window/TransitionFilter.java
+++ b/core/java/android/window/TransitionFilter.java
@@ -17,6 +17,7 @@
package android.window;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.view.WindowManager.TransitionType;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -52,7 +53,7 @@
* When non-null: this is a list of transition types that this filter applies to. This filter
* will fail for transitions that aren't one of these types.
*/
- @Nullable public int[] mTypeSet = null;
+ @Nullable public @TransitionType int[] mTypeSet = null;
/**
* A list of required changes. To pass, a transition must meet all requirements.
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index ebc66ef..a814399 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -29,6 +29,8 @@
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.view.WindowManager.TransitionFlags;
+import static android.view.WindowManager.TransitionType;
import static android.view.WindowManager.transitTypeToString;
import android.annotation.IntDef;
@@ -42,7 +44,6 @@
import android.os.Parcelable;
import android.view.Surface;
import android.view.SurfaceControl;
-import android.view.WindowManager;
import java.util.ArrayList;
import java.util.List;
@@ -106,8 +107,8 @@
})
public @interface ChangeFlags {}
- private final @WindowManager.TransitionOldType int mType;
- private final @WindowManager.TransitionFlags int mFlags;
+ private final @TransitionType int mType;
+ private final @TransitionFlags int mFlags;
private final ArrayList<Change> mChanges = new ArrayList<>();
private SurfaceControl mRootLeash;
@@ -116,8 +117,7 @@
private AnimationOptions mOptions;
/** @hide */
- public TransitionInfo(@WindowManager.TransitionOldType int type,
- @WindowManager.TransitionFlags int flags) {
+ public TransitionInfo(@TransitionType int type, @TransitionFlags int flags) {
mType = type;
mFlags = flags;
}
@@ -173,7 +173,7 @@
mOptions = options;
}
- public int getType() {
+ public @TransitionType int getType() {
return mType;
}
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 3c360fb..a735bbc 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -410,7 +410,6 @@
/**
* Creates a new TaskFragment with the given options.
* @param taskFragmentOptions the options used to create the TaskFragment.
- * @hide
*/
@NonNull
public WindowContainerTransaction createTaskFragment(
@@ -426,7 +425,6 @@
/**
* Deletes an existing TaskFragment. Any remaining activities below it will be destroyed.
* @param taskFragment the TaskFragment to be removed.
- * @hide
*/
@NonNull
public WindowContainerTransaction deleteTaskFragment(
@@ -442,20 +440,21 @@
/**
* Starts an activity in the TaskFragment.
* @param fragmentToken client assigned unique token to create TaskFragment with specified in
- * {@link TaskFragmentCreationParams#fragmentToken}.
+ * {@link TaskFragmentCreationParams#getFragmentToken()}.
+ * @param callerToken the activity token that initialized the activity launch.
* @param activityIntent intent to start the activity.
* @param activityOptions ActivityOptions to start the activity with.
* @see android.content.Context#startActivity(Intent, Bundle).
- * @hide
*/
@NonNull
public WindowContainerTransaction startActivityInTaskFragment(
- @NonNull IBinder fragmentToken, @NonNull Intent activityIntent,
- @Nullable Bundle activityOptions) {
+ @NonNull IBinder fragmentToken, @NonNull IBinder callerToken,
+ @NonNull Intent activityIntent, @Nullable Bundle activityOptions) {
final HierarchyOp hierarchyOp =
new HierarchyOp.Builder(
HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT)
.setContainer(fragmentToken)
+ .setReparentContainer(callerToken)
.setActivityIntent(activityIntent)
.setLaunchOptions(activityOptions)
.build();
@@ -466,9 +465,8 @@
/**
* Moves an activity into the TaskFragment.
* @param fragmentToken client assigned unique token to create TaskFragment with specified in
- * {@link TaskFragmentCreationParams#fragmentToken}.
+ * {@link TaskFragmentCreationParams#getFragmentToken()}.
* @param activityToken activity to be reparented.
- * @hide
*/
@NonNull
public WindowContainerTransaction reparentActivityToTaskFragment(
@@ -488,7 +486,6 @@
* @param oldParent children of this TaskFragment will be reparented.
* @param newParent the new parent TaskFragment to move the children to. If {@code null}, the
* children will be moved to the leaf Task.
- * @hide
*/
@NonNull
public WindowContainerTransaction reparentChildren(
@@ -504,12 +501,35 @@
}
/**
+ * Sets to TaskFragments adjacent to each other. Containers below two visible adjacent
+ * TaskFragments will be made invisible. This is similar to
+ * {@link #setAdjacentRoots(WindowContainerToken, WindowContainerToken)}, but can be used with
+ * fragmentTokens when that TaskFragments haven't been created (but will be created in the same
+ * {@link WindowContainerTransaction}).
+ * @param fragmentToken1 client assigned unique token to create TaskFragment with specified
+ * in {@link TaskFragmentCreationParams#getFragmentToken()}.
+ * @param fragmentToken2 client assigned unique token to create TaskFragment with specified
+ * in {@link TaskFragmentCreationParams#getFragmentToken()}.
+ * @hide
+ */
+ @NonNull
+ public WindowContainerTransaction setAdjacentTaskFragments(
+ @NonNull IBinder fragmentToken1, @NonNull IBinder fragmentToken2) {
+ final HierarchyOp hierarchyOp =
+ new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS)
+ .setContainer(fragmentToken1)
+ .setReparentContainer(fragmentToken2)
+ .build();
+ mHierarchyOps.add(hierarchyOp);
+ return this;
+ }
+
+ /**
* When this {@link WindowContainerTransaction} failed to finish on the server side, it will
* trigger callback with this {@param errorCallbackToken}.
* @param errorCallbackToken client provided token that will be passed back as parameter in
* the callback if there is an error on the server side.
* @see ITaskFragmentOrganizer#onTaskFragmentError
- * @hide
*/
@NonNull
public WindowContainerTransaction setErrorCallbackToken(@NonNull IBinder errorCallbackToken) {
@@ -906,6 +926,7 @@
public static final int HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT = 10;
public static final int HIERARCHY_OP_TYPE_REPARENT_CHILDREN = 11;
public static final int HIERARCHY_OP_TYPE_PENDING_INTENT = 12;
+ public static final int HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS = 13;
// The following key(s) are for use with mLaunchOptions:
// When launching a task (eg. from recents), this is the taskId to be launched.
@@ -1060,6 +1081,11 @@
return mReparent;
}
+ @NonNull
+ public IBinder getCallingActivity() {
+ return mReparent;
+ }
+
public boolean getToTop() {
return mToTop;
}
@@ -1129,6 +1155,9 @@
case HIERARCHY_OP_TYPE_REPARENT_CHILDREN:
return "{ReparentChildren: oldParent=" + mContainer + " newParent=" + mReparent
+ "}";
+ case HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS:
+ return "{SetAdjacentTaskFragments: container=" + mContainer
+ + " adjacentContainer=" + mReparent + "}";
default:
return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent
+ " mToTop=" + mToTop + " mWindowingMode=" + mWindowingModes
diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
index c57afbc..179ac8b 100644
--- a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
+++ b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
@@ -17,6 +17,7 @@
package com.android.internal.accessibility.util;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
@@ -30,6 +31,7 @@
import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON;
import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON_LONG_PRESS;
import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_FLOATING_MENU;
+import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_GESTURE;
import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__TRIPLE_TAP;
import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__UNKNOWN_TYPE;
import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__VOLUME_KEY;
@@ -152,19 +154,29 @@
convertToLoggingMagnificationMode(mode));
}
- private static boolean isFloatingMenuEnabled(Context context) {
+ private static boolean isAccessibilityFloatingMenuEnabled(Context context) {
return Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, /* def= */ -1)
== ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
}
+ private static boolean isAccessibilityGestureEnabled(Context context) {
+ return Settings.Secure.getInt(context.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_BUTTON_MODE, /* def= */ -1)
+ == ACCESSIBILITY_BUTTON_MODE_GESTURE;
+ }
+
private static int convertToLoggingShortcutType(Context context,
@ShortcutType int shortcutType) {
switch (shortcutType) {
case ACCESSIBILITY_BUTTON:
- return isFloatingMenuEnabled(context)
- ? ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_FLOATING_MENU
- : ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON;
+ if (isAccessibilityFloatingMenuEnabled(context)) {
+ return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_FLOATING_MENU;
+ } else if (isAccessibilityGestureEnabled(context)) {
+ return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_GESTURE;
+ } else {
+ return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON;
+ }
case ACCESSIBILITY_SHORTCUT_KEY:
return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__VOLUME_KEY;
}
diff --git a/core/java/com/android/internal/app/AbstractResolverComparator.java b/core/java/com/android/internal/app/AbstractResolverComparator.java
index 40ada0b..c00d16c 100644
--- a/core/java/com/android/internal/app/AbstractResolverComparator.java
+++ b/core/java/com/android/internal/app/AbstractResolverComparator.java
@@ -22,6 +22,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.os.BadParcelableException;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -109,17 +110,22 @@
// get annotations of content from intent.
private void getContentAnnotations(Intent intent) {
- ArrayList<String> annotations = intent.getStringArrayListExtra(
- Intent.EXTRA_CONTENT_ANNOTATIONS);
- if (annotations != null) {
- int size = annotations.size();
- if (size > NUM_OF_TOP_ANNOTATIONS_TO_USE) {
- size = NUM_OF_TOP_ANNOTATIONS_TO_USE;
+ try {
+ ArrayList<String> annotations = intent.getStringArrayListExtra(
+ Intent.EXTRA_CONTENT_ANNOTATIONS);
+ if (annotations != null) {
+ int size = annotations.size();
+ if (size > NUM_OF_TOP_ANNOTATIONS_TO_USE) {
+ size = NUM_OF_TOP_ANNOTATIONS_TO_USE;
+ }
+ mAnnotations = new String[size];
+ for (int i = 0; i < size; i++) {
+ mAnnotations[i] = annotations.get(i);
+ }
}
- mAnnotations = new String[size];
- for (int i = 0; i < size; i++) {
- mAnnotations[i] = annotations.get(i);
- }
+ } catch (BadParcelableException e) {
+ Log.i(TAG, "Couldn't unparcel intent annotations. Ignoring.");
+ mAnnotations = new String[0];
}
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index eeceafa..786af5f 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -1269,7 +1269,8 @@
SELECTION_TYPE_NEARBY,
"",
-1);
- safelyStartActivity(ti);
+ // Action bar is user-independent, always start as primary
+ safelyStartActivityAsUser(ti, getPersonalProfileUserHandle());
finish();
}
);
@@ -1290,7 +1291,8 @@
SELECTION_TYPE_EDIT,
"",
-1);
- safelyStartActivity(ti);
+ // Action bar is user-independent, always start as primary
+ safelyStartActivityAsUser(ti, getPersonalProfileUserHandle());
finish();
}
);
@@ -3452,8 +3454,6 @@
private View createProfileView(ViewGroup parent) {
View profileRow = mLayoutInflater.inflate(R.layout.chooser_profile_row, parent, false);
- profileRow.setBackground(
- getResources().getDrawable(R.drawable.chooser_row_layer_list, null));
mProfileView = profileRow.findViewById(R.id.profile_button);
mProfileView.setOnClickListener(ChooserActivity.this::onProfileClick);
updateProfileViewButton();
@@ -3599,10 +3599,6 @@
final ViewGroup viewGroup = (ViewGroup) holder.itemView;
int start = getListPosition(position);
int startType = getRowType(start);
- if (viewGroup.getForeground() == null && position > 0) {
- viewGroup.setForeground(
- getResources().getDrawable(R.drawable.chooser_row_layer_list, null));
- }
int columnCount = holder.getColumnCount();
int end = start + columnCount - 1;
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 6f9da6f..d08f21c 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1257,13 +1257,32 @@
// don't kill ourselves.
StrictMode.disableDeathOnFileUriExposure();
try {
- safelyStartActivityInternal(cti);
+ UserHandle currentUserHandle = mMultiProfilePagerAdapter.getCurrentUserHandle();
+ safelyStartActivityInternal(cti, currentUserHandle);
} finally {
StrictMode.enableDeathOnFileUriExposure();
}
}
- private void safelyStartActivityInternal(TargetInfo cti) {
+ /**
+ * Start activity as a fixed user handle.
+ * @param cti TargetInfo to be launched.
+ * @param user User to launch this activity as.
+ */
+ @VisibleForTesting
+ public void safelyStartActivityAsUser(TargetInfo cti, UserHandle user) {
+ // We're dispatching intents that might be coming from legacy apps, so
+ // don't kill ourselves.
+ StrictMode.disableDeathOnFileUriExposure();
+ try {
+ safelyStartActivityInternal(cti, user);
+ } finally {
+ StrictMode.enableDeathOnFileUriExposure();
+ }
+ }
+
+
+ private void safelyStartActivityInternal(TargetInfo cti, UserHandle user) {
// If the target is suspended, the activity will not be successfully launched.
// Do not unregister from package manager updates in this case
if (!cti.isSuspended() && mRegistered) {
@@ -1280,18 +1299,17 @@
if (mProfileSwitchMessageId != -1) {
Toast.makeText(this, getString(mProfileSwitchMessageId), Toast.LENGTH_LONG).show();
}
- UserHandle currentUserHandle = mMultiProfilePagerAdapter.getCurrentUserHandle();
if (!mSafeForwardingMode) {
- if (cti.startAsUser(this, null, currentUserHandle)) {
+ if (cti.startAsUser(this, null, user)) {
onActivityStarted(cti);
- maybeLogCrossProfileTargetLaunch(cti, currentUserHandle);
+ maybeLogCrossProfileTargetLaunch(cti, user);
}
return;
}
try {
- if (cti.startAsCaller(this, null, currentUserHandle.getIdentifier())) {
+ if (cti.startAsCaller(this, null, user.getIdentifier())) {
onActivityStarted(cti);
- maybeLogCrossProfileTargetLaunch(cti, currentUserHandle);
+ maybeLogCrossProfileTargetLaunch(cti, user);
}
} catch (RuntimeException e) {
Slog.wtf(TAG, "Unable to launch as uid " + mLaunchedFromUid
diff --git a/core/java/com/android/internal/display/BrightnessSynchronizer.java b/core/java/com/android/internal/display/BrightnessSynchronizer.java
index c9a9e51..55a2052 100644
--- a/core/java/com/android/internal/display/BrightnessSynchronizer.java
+++ b/core/java/com/android/internal/display/BrightnessSynchronizer.java
@@ -16,9 +16,11 @@
package com.android.internal.display;
+import android.annotation.NonNull;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
+import android.hardware.display.BrightnessInfo;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.net.Uri;
@@ -61,10 +63,10 @@
updateBrightnessFloatFromInt(msg.arg1);
break;
case MSG_UPDATE_INT:
- updateBrightnessIntFromFloat(Float.intBitsToFloat(msg.arg1));
+ updateBrightnessIntFromFloat((BrightnessInfo) msg.obj);
break;
case MSG_UPDATE_BOTH:
- updateBoth(Float.intBitsToFloat(msg.arg1));
+ updateBoth((BrightnessInfo) msg.obj, Float.intBitsToFloat(msg.arg1));
break;
default:
super.handleMessage(msg);
@@ -95,11 +97,11 @@
brightnessSyncObserver = new BrightnessSyncObserver();
brightnessSyncObserver.startObserving();
- final float currentFloatBrightness = getScreenBrightnessFloat();
+ final BrightnessInfo brightnessInfo = getBrightnessInfo();
final int currentIntBrightness = getScreenBrightnessInt(mContext);
- if (!Float.isNaN(currentFloatBrightness)) {
- updateBrightnessIntFromFloat(currentFloatBrightness);
+ if (brightnessInfo != null && !Float.isNaN(brightnessInfo.brightness)) {
+ updateBrightnessIntFromFloat(brightnessInfo);
} else if (currentIntBrightness != -1) {
updateBrightnessFloatFromInt(currentIntBrightness);
} else {
@@ -112,15 +114,23 @@
/**
* Converts between the int brightness system and the float brightness system.
+ *
+ * @param brightnessInt The int brightness value to convert.
*/
public static float brightnessIntToFloat(int brightnessInt) {
+ return brightnessIntToFloat(brightnessInt, null);
+ }
+
+ private static float brightnessIntToFloat(int brightnessInt, BrightnessInfo info) {
if (brightnessInt == PowerManager.BRIGHTNESS_OFF) {
return PowerManager.BRIGHTNESS_OFF_FLOAT;
} else if (brightnessInt == PowerManager.BRIGHTNESS_INVALID) {
return PowerManager.BRIGHTNESS_INVALID_FLOAT;
} else {
- final float minFloat = PowerManager.BRIGHTNESS_MIN;
- final float maxFloat = PowerManager.BRIGHTNESS_MAX;
+ final float minFloat = info != null
+ ? info.brightnessMinimum : PowerManager.BRIGHTNESS_MIN;
+ final float maxFloat = info != null
+ ? info.brightnessMaximum : PowerManager.BRIGHTNESS_MAX;
final float minInt = PowerManager.BRIGHTNESS_OFF + 1;
final float maxInt = PowerManager.BRIGHTNESS_ON;
return MathUtils.constrainedMap(minFloat, maxFloat, minInt, maxInt, brightnessInt);
@@ -128,29 +138,28 @@
}
/**
- * Converts between the float brightness system and the int brightness system.
- */
- public static int brightnessFloatToInt(float brightnessFloat) {
- return Math.round(brightnessFloatToIntRange(brightnessFloat));
- }
-
- /**
* Translates specified value from the float brightness system to the int brightness system,
* given the min/max of each range. Accounts for special values such as OFF and invalid values.
* Value returned as a float primitive (to preserve precision), but is a value within the
* int-system range.
+ *
+ * @param brightnessFloat The float brightness value to convert.
+ * @param info Brightness information to use in the conversion.
*/
- public static float brightnessFloatToIntRange(float brightnessFloat) {
+ public static int brightnessFloatToInt(float brightnessFloat, BrightnessInfo info) {
if (floatEquals(brightnessFloat, PowerManager.BRIGHTNESS_OFF_FLOAT)) {
return PowerManager.BRIGHTNESS_OFF;
} else if (Float.isNaN(brightnessFloat)) {
return PowerManager.BRIGHTNESS_INVALID;
} else {
- final float minFloat = PowerManager.BRIGHTNESS_MIN;
- final float maxFloat = PowerManager.BRIGHTNESS_MAX;
+ final float minFloat = info != null
+ ? info.brightnessMinimum : PowerManager.BRIGHTNESS_MIN;
+ final float maxFloat = info != null
+ ? info.brightnessMaximum : PowerManager.BRIGHTNESS_MAX;
final float minInt = PowerManager.BRIGHTNESS_OFF + 1;
final float maxInt = PowerManager.BRIGHTNESS_ON;
- return MathUtils.constrainedMap(minInt, maxInt, minFloat, maxFloat, brightnessFloat);
+ return Math.round(MathUtils.constrainedMap(minInt, maxInt, minFloat, maxFloat,
+ brightnessFloat));
}
}
@@ -185,35 +194,37 @@
* @param value Brightness value as int to store in the float setting.
*/
private void updateBrightnessFloatFromInt(int value) {
- if (brightnessFloatToInt(mPreferredSettingValue) == value) {
+ final BrightnessInfo info = getBrightnessInfo();
+ if (brightnessFloatToInt(mPreferredSettingValue, info) == value) {
return;
}
- mPreferredSettingValue = brightnessIntToFloat(value);
+ mPreferredSettingValue = brightnessIntToFloat(value, info);
final int newBrightnessAsIntBits = Float.floatToIntBits(mPreferredSettingValue);
mHandler.removeMessages(MSG_UPDATE_BOTH);
mHandler.obtainMessage(MSG_UPDATE_BOTH, newBrightnessAsIntBits, 0).sendToTarget();
}
/**
- * Updates the settings based on a passed in float value. This is called whenever the float
- * setting changes. mPreferredSettingValue holds the most recently updated brightness value
- * as a float that we would like the display to be set to.
+ * Updates the settings from the specified {@link BrightnessInfo}. This is called whenever the
+ * float brightness changed from DisplayManager. mPreferredSettingValue holds the most recently
+ * updated brightness value as a float that we would like the display to be set to.
*
* We then schedule an update to both the int and float settings, but, remove all the other
* messages to update all, to prevent us getting stuck in a loop.
*
- * @param value Brightness setting as float to store in int setting.
+ * @param brightnessInfo Current brightness information
*/
- private void updateBrightnessIntFromFloat(float value) {
+ private void updateBrightnessIntFromFloat(@NonNull BrightnessInfo brightnessInfo) {
+ final float value = brightnessInfo.brightness;
if (floatEquals(mPreferredSettingValue, value)) {
return;
}
mPreferredSettingValue = value;
- final int newBrightnessAsIntBits = Float.floatToIntBits(mPreferredSettingValue);
mHandler.removeMessages(MSG_UPDATE_BOTH);
- mHandler.obtainMessage(MSG_UPDATE_BOTH, newBrightnessAsIntBits, 0).sendToTarget();
+ mHandler.obtainMessage(MSG_UPDATE_BOTH, Float.floatToIntBits(value), 0, brightnessInfo)
+ .sendToTarget();
}
@@ -222,16 +233,24 @@
* mDisplayManager.setBrightness automatically checks for changes
* Settings.System.putIntForUser needs to be checked, to prevent an extra callback to this class
*
+ * @param brightnessInfo Brightness information, takes precedent over newBrightnessFloat
* @param newBrightnessFloat Brightness setting as float to store in both settings
*/
- private void updateBoth(float newBrightnessFloat) {
- int newBrightnessInt = brightnessFloatToInt(newBrightnessFloat);
+ private void updateBoth(BrightnessInfo brightnessInfo, float newBrightnessFloat) {
+ int newBrightnessInt = brightnessFloatToInt(newBrightnessFloat, brightnessInfo);
mDisplayManager.setBrightness(Display.DEFAULT_DISPLAY, newBrightnessFloat);
if (getScreenBrightnessInt(mContext) != newBrightnessInt) {
Settings.System.putIntForUser(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS, newBrightnessInt, UserHandle.USER_CURRENT);
}
+ }
+ private BrightnessInfo getBrightnessInfo() {
+ final Display display = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
+ if (display != null) {
+ return display.getBrightnessInfo();
+ }
+ return null;
}
/**
@@ -263,10 +282,15 @@
@Override
public void onDisplayChanged(int displayId) {
- float currentFloat = getScreenBrightnessFloat();
- int toSend = Float.floatToIntBits(currentFloat);
- mHandler.removeMessages(MSG_UPDATE_INT);
- mHandler.obtainMessage(MSG_UPDATE_INT, toSend, 0).sendToTarget();
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ return;
+ }
+
+ final BrightnessInfo info = getBrightnessInfo();
+ if (info != null) {
+ mHandler.removeMessages(MSG_UPDATE_INT);
+ mHandler.obtainMessage(MSG_UPDATE_INT, info).sendToTarget();
+ }
}
};
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index 6ce7cea..be91aac 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -220,8 +220,9 @@
public CallSession callStarted(Binder binder, int code, int workSourceUid) {
noteNativeThreadId();
+ boolean collectCpu = canCollect();
// We always want to collect data for latency if it's enabled, regardless of device state.
- if (!mCollectLatencyData && !canCollect()) {
+ if (!mCollectLatencyData && !collectCpu) {
return null;
}
@@ -233,7 +234,7 @@
s.timeStarted = -1;
s.recordedCall = shouldRecordDetailedData();
- if (mRecordingAllTransactionsForUid || s.recordedCall) {
+ if (collectCpu && (mRecordingAllTransactionsForUid || s.recordedCall)) {
s.cpuTimeStarted = getThreadTimeMicro();
s.timeStarted = getElapsedRealtimeMicro();
} else if (mCollectLatencyData) {
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 4f940db..84a7f2f 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -25,7 +25,7 @@
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.service.notification.StatusBarNotification;
-import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.view.AppearanceRegion;
@@ -192,12 +192,12 @@
* stacks.
* @param navbarColorManagedByIme {@code true} if navigation bar color is managed by IME.
* @param behavior the behavior of the focused window.
- * @param requestedState the collection of the requested visibilities of system insets.
+ * @param requestedVisibilities the collection of the requested visibilities of system insets.
* @param packageName the package name of the focused app.
*/
void onSystemBarAttributesChanged(int displayId, int appearance,
in AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- int behavior, in InsetsState requestedVisibilities, String packageName);
+ int behavior, in InsetsVisibilities requestedVisibilities, String packageName);
/**
* Notifies System UI to show transient bars. The transient bars are system bars, e.g., status
diff --git a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
index 2fd1691..4dcc82e 100644
--- a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
+++ b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
@@ -21,7 +21,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArrayMap;
-import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import com.android.internal.view.AppearanceRegion;
@@ -40,14 +40,14 @@
public final IBinder mImeToken;
public final boolean mNavbarColorManagedByIme;
public final int mBehavior;
- public final InsetsState mRequestedState;
+ public final InsetsVisibilities mRequestedVisibilities;
public final String mPackageName;
public final int[] mTransientBarTypes;
public RegisterStatusBarResult(ArrayMap<String, StatusBarIcon> icons, int disabledFlags1,
int appearance, AppearanceRegion[] appearanceRegions, int imeWindowVis,
int imeBackDisposition, boolean showImeSwitcher, int disabledFlags2, IBinder imeToken,
- boolean navbarColorManagedByIme, int behavior, InsetsState requestedState,
+ boolean navbarColorManagedByIme, int behavior, InsetsVisibilities requestedVisibilities,
String packageName, @NonNull int[] transientBarTypes) {
mIcons = new ArrayMap<>(icons);
mDisabledFlags1 = disabledFlags1;
@@ -60,7 +60,7 @@
mImeToken = imeToken;
mNavbarColorManagedByIme = navbarColorManagedByIme;
mBehavior = behavior;
- mRequestedState = requestedState;
+ mRequestedVisibilities = requestedVisibilities;
mPackageName = packageName;
mTransientBarTypes = transientBarTypes;
}
@@ -83,7 +83,7 @@
dest.writeStrongBinder(mImeToken);
dest.writeBoolean(mNavbarColorManagedByIme);
dest.writeInt(mBehavior);
- dest.writeTypedObject(mRequestedState, 0);
+ dest.writeTypedObject(mRequestedVisibilities, 0);
dest.writeString(mPackageName);
dest.writeIntArray(mTransientBarTypes);
}
@@ -108,13 +108,14 @@
final IBinder imeToken = source.readStrongBinder();
final boolean navbarColorManagedByIme = source.readBoolean();
final int behavior = source.readInt();
- final InsetsState requestedState = source.readTypedObject(InsetsState.CREATOR);
+ final InsetsVisibilities requestedVisibilities =
+ source.readTypedObject(InsetsVisibilities.CREATOR);
final String packageName = source.readString();
final int[] transientBarTypes = source.createIntArray();
return new RegisterStatusBarResult(icons, disabledFlags1, appearance,
appearanceRegions, imeWindowVis, imeBackDisposition, showImeSwitcher,
disabledFlags2, imeToken, navbarColorManagedByIme, behavior,
- requestedState, packageName, transientBarTypes);
+ requestedVisibilities, packageName, transientBarTypes);
}
@Override
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index a8dcbaf..6cbace4 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -241,7 +241,11 @@
private final ArraySet<String> mRollbackWhitelistedPackages = new ArraySet<>();
private final ArraySet<String> mWhitelistedStagedInstallers = new ArraySet<>();
- private final ArraySet<String> mAllowedVendorApexes = new ArraySet<>();
+ // A map from package name of vendor APEXes that can be updated to an installer package name
+ // allowed to install updates for it.
+ private final ArrayMap<String, String> mAllowedVendorApexes = new ArrayMap<>();
+
+ private String mModulesInstallerPackageName;
/**
* Map of system pre-defined, uniquely named actors; keys are namespace,
@@ -412,10 +416,14 @@
return mWhitelistedStagedInstallers;
}
- public Set<String> getAllowedVendorApexes() {
+ public Map<String, String> getAllowedVendorApexes() {
return mAllowedVendorApexes;
}
+ public String getModulesInstallerPackageName() {
+ return mModulesInstallerPackageName;
+ }
+
public ArraySet<String> getAppDataIsolationWhitelistedApps() {
return mAppDataIsolationWhitelistedApps;
}
@@ -1210,12 +1218,21 @@
case "whitelisted-staged-installer": {
if (allowAppConfigs) {
String pkgname = parser.getAttributeValue(null, "package");
+ boolean isModulesInstaller = XmlUtils.readBooleanAttribute(
+ parser, "isModulesInstaller", false);
if (pkgname == null) {
Slog.w(TAG, "<" + name + "> without package in " + permFile
+ " at " + parser.getPositionDescription());
} else {
mWhitelistedStagedInstallers.add(pkgname);
}
+ if (isModulesInstaller) {
+ if (mModulesInstallerPackageName != null) {
+ throw new IllegalStateException(
+ "Multiple modules installers");
+ }
+ mModulesInstallerPackageName = pkgname;
+ }
} else {
logNotAllowedInPartition(name, permFile, parser);
}
@@ -1224,11 +1241,18 @@
case "allowed-vendor-apex": {
if (allowVendorApex) {
String pkgName = parser.getAttributeValue(null, "package");
+ String installerPkgName = parser.getAttributeValue(
+ null, "installerPackage");
if (pkgName == null) {
Slog.w(TAG, "<" + name + "> without package in " + permFile
+ " at " + parser.getPositionDescription());
- } else {
- mAllowedVendorApexes.add(pkgName);
+ }
+ if (installerPkgName == null) {
+ Slog.w(TAG, "<" + name + "> without installerPackage in " + permFile
+ + " at " + parser.getPositionDescription());
+ }
+ if (pkgName != null && installerPkgName != null) {
+ mAllowedVendorApexes.put(pkgName, installerPkgName);
}
} else {
logNotAllowedInPartition(name, permFile, parser);
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 1d07c26..98fc84c 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -146,6 +146,7 @@
"android_os_MemoryFile.cpp",
"android_os_MessageQueue.cpp",
"android_os_Parcel.cpp",
+ "android_os_PerformanceHintManager.cpp",
"android_os_SELinux.cpp",
"android_os_ServiceManager.cpp",
"android_os_SharedMemory.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 406ccde..2fd1e54 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -143,6 +143,7 @@
extern int register_android_os_ServiceManager(JNIEnv *env);
extern int register_android_os_MessageQueue(JNIEnv* env);
extern int register_android_os_Parcel(JNIEnv* env);
+extern int register_android_os_PerformanceHintManager(JNIEnv* env);
extern int register_android_os_SELinux(JNIEnv* env);
extern int register_android_os_VintfObject(JNIEnv *env);
extern int register_android_os_VintfRuntimeInfo(JNIEnv *env);
@@ -1518,6 +1519,7 @@
REG_JNI(register_android_os_SystemProperties),
REG_JNI(register_android_os_Binder),
REG_JNI(register_android_os_Parcel),
+ REG_JNI(register_android_os_PerformanceHintManager),
REG_JNI(register_android_os_HidlMemory),
REG_JNI(register_android_os_HidlSupport),
REG_JNI(register_android_os_HwBinder),
diff --git a/core/jni/android_os_PerformanceHintManager.cpp b/core/jni/android_os_PerformanceHintManager.cpp
new file mode 100644
index 0000000..d05a24f
--- /dev/null
+++ b/core/jni/android_os_PerformanceHintManager.cpp
@@ -0,0 +1,155 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "PerfHint-jni"
+
+#include "jni.h"
+
+#include <dlfcn.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <utils/Log.h>
+#include <vector>
+
+#include "core_jni_helpers.h"
+
+namespace android {
+
+namespace {
+
+struct APerformanceHintManager;
+struct APerformanceHintSession;
+
+typedef APerformanceHintManager* (*APH_getManager)();
+typedef APerformanceHintSession* (*APH_createSession)(APerformanceHintManager*, const int32_t*,
+ size_t, int64_t);
+typedef int64_t (*APH_getPreferredUpdateRateNanos)(APerformanceHintManager* manager);
+typedef void (*APH_updateTargetWorkDuration)(APerformanceHintSession*, int64_t);
+typedef void (*APH_reportActualWorkDuration)(APerformanceHintSession*, int64_t);
+typedef void (*APH_closeSession)(APerformanceHintSession* session);
+
+bool gAPerformanceHintBindingInitialized = false;
+APH_getManager gAPH_getManagerFn = nullptr;
+APH_createSession gAPH_createSessionFn = nullptr;
+APH_getPreferredUpdateRateNanos gAPH_getPreferredUpdateRateNanosFn = nullptr;
+APH_updateTargetWorkDuration gAPH_updateTargetWorkDurationFn = nullptr;
+APH_reportActualWorkDuration gAPH_reportActualWorkDurationFn = nullptr;
+APH_closeSession gAPH_closeSessionFn = nullptr;
+
+void ensureAPerformanceHintBindingInitialized() {
+ if (gAPerformanceHintBindingInitialized) return;
+
+ void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
+ LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!");
+
+ gAPH_getManagerFn = (APH_getManager)dlsym(handle_, "APerformanceHint_getManager");
+ LOG_ALWAYS_FATAL_IF(gAPH_getManagerFn == nullptr,
+ "Failed to find required symbol APerformanceHint_getManager!");
+
+ gAPH_createSessionFn = (APH_createSession)dlsym(handle_, "APerformanceHint_createSession");
+ LOG_ALWAYS_FATAL_IF(gAPH_createSessionFn == nullptr,
+ "Failed to find required symbol APerformanceHint_createSession!");
+
+ gAPH_getPreferredUpdateRateNanosFn =
+ (APH_getPreferredUpdateRateNanos)dlsym(handle_,
+ "APerformanceHint_getPreferredUpdateRateNanos");
+ LOG_ALWAYS_FATAL_IF(gAPH_getPreferredUpdateRateNanosFn == nullptr,
+ "Failed to find required symbol "
+ "APerformanceHint_getPreferredUpdateRateNanos!");
+
+ gAPH_updateTargetWorkDurationFn =
+ (APH_updateTargetWorkDuration)dlsym(handle_,
+ "APerformanceHint_updateTargetWorkDuration");
+ LOG_ALWAYS_FATAL_IF(gAPH_updateTargetWorkDurationFn == nullptr,
+ "Failed to find required symbol "
+ "APerformanceHint_updateTargetWorkDuration!");
+
+ gAPH_reportActualWorkDurationFn =
+ (APH_reportActualWorkDuration)dlsym(handle_,
+ "APerformanceHint_reportActualWorkDuration");
+ LOG_ALWAYS_FATAL_IF(gAPH_reportActualWorkDurationFn == nullptr,
+ "Failed to find required symbol "
+ "APerformanceHint_reportActualWorkDuration!");
+
+ gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSession");
+ LOG_ALWAYS_FATAL_IF(gAPH_closeSessionFn == nullptr,
+ "Failed to find required symbol APerformanceHint_closeSession!");
+
+ gAPerformanceHintBindingInitialized = true;
+}
+
+} // namespace
+
+static jlong nativeAcquireManager(JNIEnv* env, jclass clazz) {
+ ensureAPerformanceHintBindingInitialized();
+ return reinterpret_cast<jlong>(gAPH_getManagerFn());
+}
+
+static jlong nativeGetPreferredUpdateRateNanos(JNIEnv* env, jclass clazz, jlong nativeManagerPtr) {
+ ensureAPerformanceHintBindingInitialized();
+ return gAPH_getPreferredUpdateRateNanosFn(
+ reinterpret_cast<APerformanceHintManager*>(nativeManagerPtr));
+}
+
+static jlong nativeCreateSession(JNIEnv* env, jclass clazz, jlong nativeManagerPtr, jintArray tids,
+ jlong initialTargetWorkDurationNanos) {
+ ensureAPerformanceHintBindingInitialized();
+ if (tids == nullptr) return 0;
+ std::vector<int32_t> tidsVector;
+ ScopedIntArrayRO tidsArray(env, tids);
+ for (size_t i = 0; i < tidsArray.size(); ++i) {
+ tidsVector.push_back(static_cast<int32_t>(tidsArray[i]));
+ }
+ return reinterpret_cast<jlong>(
+ gAPH_createSessionFn(reinterpret_cast<APerformanceHintManager*>(nativeManagerPtr),
+ tidsVector.data(), tidsVector.size(),
+ initialTargetWorkDurationNanos));
+}
+
+static void nativeUpdateTargetWorkDuration(JNIEnv* env, jclass clazz, jlong nativeSessionPtr,
+ jlong targetDurationNanos) {
+ ensureAPerformanceHintBindingInitialized();
+ gAPH_updateTargetWorkDurationFn(reinterpret_cast<APerformanceHintSession*>(nativeSessionPtr),
+ targetDurationNanos);
+}
+
+static void nativeReportActualWorkDuration(JNIEnv* env, jclass clazz, jlong nativeSessionPtr,
+ jlong actualDurationNanos) {
+ ensureAPerformanceHintBindingInitialized();
+ gAPH_reportActualWorkDurationFn(reinterpret_cast<APerformanceHintSession*>(nativeSessionPtr),
+ actualDurationNanos);
+}
+
+static void nativeCloseSession(JNIEnv* env, jclass clazz, jlong nativeSessionPtr) {
+ ensureAPerformanceHintBindingInitialized();
+ gAPH_closeSessionFn(reinterpret_cast<APerformanceHintSession*>(nativeSessionPtr));
+}
+
+static const JNINativeMethod gPerformanceHintMethods[] = {
+ {"nativeAcquireManager", "()J", (void*)nativeAcquireManager},
+ {"nativeGetPreferredUpdateRateNanos", "(J)J", (void*)nativeGetPreferredUpdateRateNanos},
+ {"nativeCreateSession", "(J[IJ)J", (void*)nativeCreateSession},
+ {"nativeUpdateTargetWorkDuration", "(JJ)V", (void*)nativeUpdateTargetWorkDuration},
+ {"nativeReportActualWorkDuration", "(JJ)V", (void*)nativeReportActualWorkDuration},
+ {"nativeCloseSession", "(J)V", (void*)nativeCloseSession},
+};
+
+int register_android_os_PerformanceHintManager(JNIEnv* env) {
+ return RegisterMethodsOrDie(env, "android/os/PerformanceHintManager", gPerformanceHintMethods,
+ NELEM(gPerformanceHintMethods));
+}
+
+} // namespace android
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index dd80c73..50cd70f 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -825,6 +825,14 @@
transaction->setShadowRadius(ctrl, shadowRadius);
}
+static void nativeSetTrustedOverlay(JNIEnv* env, jclass clazz, jlong transactionObj,
+ jlong nativeObject, jboolean isTrustedOverlay) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
+ SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ transaction->setTrustedOverlay(ctrl, isTrustedOverlay);
+}
+
static void nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject,
jfloat frameRate, jint compatibility, jint changeFrameRateStrategy) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
@@ -1999,6 +2007,8 @@
(void*)nativeSetTransformHint },
{"nativeGetTransformHint", "(J)I",
(void*)nativeGetTransformHint },
+ {"nativeSetTrustedOverlay", "(JJZ)V",
+ (void*)nativeSetTrustedOverlay },
// clang-format on
};
diff --git a/core/res/res/drawable/chooser_row_layer_list.xml b/core/res/res/drawable/chooser_row_layer_list.xml
index 0800815..f5ba1e9 100644
--- a/core/res/res/drawable/chooser_row_layer_list.xml
+++ b/core/res/res/drawable/chooser_row_layer_list.xml
@@ -17,9 +17,11 @@
*/
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:bottom="-5dp" android:left="-5dp" android:right="-5dp">
+ <item>
<shape android:shape="rectangle">
- <stroke android:width="1dp" android:color="@color/chooser_row_divider"/>
+ <solid android:color="?android:attr/colorAccentSecondary"/>
+ <size android:width="128dp" android:height="2dp"/>
+ <corners android:radius="2dp" />
</shape>
</item>
</layer-list>
diff --git a/core/res/res/layout-car/car_alert_dialog.xml b/core/res/res/layout-car/car_alert_dialog.xml
index 569e594..2e7b62c 100644
--- a/core/res/res/layout-car/car_alert_dialog.xml
+++ b/core/res/res/layout-car/car_alert_dialog.xml
@@ -54,7 +54,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/text_view_start_margin"
android:layout_marginEnd="@dimen/text_view_end_margin"
- style="@style/CarBody2"/>
+ style="@style/CarBody4"/>
<!-- we don't need this spacer, but the id needs to be here for compatibility -->
<Space
diff --git a/core/res/res/layout-car/car_alert_dialog_button_bar.xml b/core/res/res/layout-car/car_alert_dialog_button_bar.xml
index 277b0dc..4f815b8 100644
--- a/core/res/res/layout-car/car_alert_dialog_button_bar.xml
+++ b/core/res/res/layout-car/car_alert_dialog_button_bar.xml
@@ -36,6 +36,9 @@
<Button
android:id="@+id/button3"
style="@style/CarAction1"
+ android:minWidth="@dimen/car_touch_target_size"
+ android:paddingStart="@dimen/car_padding_2"
+ android:paddingEnd="@dimen/car_padding_2"
android:background="@drawable/car_dialog_button_background"
android:layout_marginRight="@dimen/button_end_margin"
android:layout_width="wrap_content"
@@ -44,6 +47,9 @@
<Button
android:id="@+id/button2"
style="@style/CarAction1"
+ android:minWidth="@dimen/car_touch_target_size"
+ android:paddingStart="@dimen/car_padding_2"
+ android:paddingEnd="@dimen/car_padding_2"
android:background="@drawable/car_dialog_button_background"
android:layout_marginRight="@dimen/button_end_margin"
android:layout_width="wrap_content"
@@ -52,6 +58,9 @@
<Button
android:id="@+id/button1"
style="@style/CarAction1"
+ android:minWidth="@dimen/car_touch_target_size"
+ android:paddingStart="@dimen/car_padding_2"
+ android:paddingEnd="@dimen/car_padding_2"
android:background="@drawable/car_dialog_button_background"
android:layout_width="wrap_content"
android:layout_height="@dimen/button_layout_height" />
diff --git a/core/res/res/layout/chooser_az_label_row.xml b/core/res/res/layout/chooser_az_label_row.xml
index 1b733fc..baf07ce 100644
--- a/core/res/res/layout/chooser_az_label_row.xml
+++ b/core/res/res/layout/chooser_az_label_row.xml
@@ -15,17 +15,12 @@
~ limitations under the License
-->
-<!-- Separator applied as background -->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:text="@string/chooser_all_apps_button_label"
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:contentDescription="@string/chooser_all_apps_button_label"
- android:background="@drawable/chooser_row_layer_list"
- android:textAppearance="?attr/textAppearanceSmall"
- android:textColor="?attr/textColorSecondary"
- android:textSize="14sp"
- android:singleLine="true"
+ android:src="@drawable/chooser_row_layer_list"
android:paddingTop="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:scaleType="center"
android:gravity="center"/>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 0970fc5..2d94ffe 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1248,9 +1248,9 @@
<string name="whichImageCaptureApplication" msgid="2737413019463215284">"Зрабіць здымак з дапамогай"</string>
<string name="whichImageCaptureApplicationNamed" msgid="8820702441847612202">"Зрабіць здымак з дапамогай %1$s"</string>
<string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"Зрабіць здымак"</string>
- <string name="alwaysUse" msgid="3153558199076112903">"Выкарыстоўваць па змаўчанні для гэтага дзеяння."</string>
+ <string name="alwaysUse" msgid="3153558199076112903">"Выкарыстоўваць стандартна для гэтага дзеяння."</string>
<string name="use_a_different_app" msgid="4987790276170972776">"Выкарыстоўваць іншую праграму"</string>
- <string name="clearDefaultHintMsg" msgid="1325866337702524936">"Ачысціць па змаўчанні ў раздзеле \"Налады сістэмы > Прыкладанні > Спампаваныя\"."</string>
+ <string name="clearDefaultHintMsg" msgid="1325866337702524936">"Ачысціць стандартныя налады ў раздзеле \"Налады сістэмы > Праграмы > Спампаваныя\"."</string>
<string name="chooseActivity" msgid="8563390197659779956">"Выберыце дзеянне"</string>
<string name="chooseUsbActivity" msgid="2096269989990986612">"Выберыце прыкладанне для USB-прылады"</string>
<string name="noApplications" msgid="1186909265235544019">"Няма прыкладанняў, якія могуць выконваць гэты працэс."</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 141cf4e..8cf968d 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -700,8 +700,8 @@
<string name="permdesc_bindConditionProviderService" msgid="6106018791256120258">"Allows the holder to bind to the top-level interface of a condition provider service. Should never be needed for normal apps."</string>
<string name="permlab_bindDreamService" msgid="4776175992848982706">"bind to a dream service"</string>
<string name="permdesc_bindDreamService" msgid="9129615743300572973">"Allows the holder to bind to the top-level interface of a dream service. Should never be needed for normal apps."</string>
- <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"invoke the carrier-provided configuration app"</string>
- <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps."</string>
+ <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"invoke the operator-provided configuration app"</string>
+ <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"Allows the holder to invoke the operator-provided configuration app. Should never be needed for normal apps."</string>
<string name="permlab_accessNetworkConditions" msgid="1270732533356286514">"listen for observations on network conditions"</string>
<string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"Allows an application to listen for observations on network conditions. Should never be needed for normal apps."</string>
<string name="permlab_setInputCalibration" msgid="932069700285223434">"change input device calibration"</string>
@@ -712,8 +712,8 @@
<string name="permdesc_handoverStatus" msgid="3842269451732571070">"Allows this application to receive information about current Android Beam transfers"</string>
<string name="permlab_removeDrmCertificates" msgid="710576248717404416">"remove DRM certificates"</string>
<string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"Allows an application to remove DRM certficates. Should never be needed for normal apps."</string>
- <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"bind to a carrier messaging service"</string>
- <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Allows the holder to bind to the top-level interface of a carrier messaging service. Should never be needed for normal apps."</string>
+ <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"bind to an operator messaging service"</string>
+ <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Allows the holder to bind to the top-level interface of an operator messaging service. Should never be needed for normal apps."</string>
<string name="permlab_bindCarrierServices" msgid="2395596978626237474">"bind to operator services"</string>
<string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"Allows the holder to bind to operator services. Should never be needed for normal apps."</string>
<string name="permlab_access_notification_policy" msgid="5524112842876975537">"access Do Not Disturb"</string>
@@ -1655,7 +1655,7 @@
<string name="kg_sim_pin_instructions" msgid="6479401489471690359">"Enter SIM PIN"</string>
<string name="kg_pin_instructions" msgid="7355933174673539021">"Enter PIN"</string>
<string name="kg_password_instructions" msgid="7179782578809398050">"Enter Password"</string>
- <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"SIM is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_pin_hint" msgid="8190982314659429770">"Enter desired PIN code"</string>
<string name="kg_enter_confirm_pin_hint" msgid="6372557107414074580">"Confirm desired PIN code"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8871937892678885545">"Unlocking SIM card…"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 2b1d3e0..b772335 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -700,8 +700,8 @@
<string name="permdesc_bindConditionProviderService" msgid="6106018791256120258">"Allows the holder to bind to the top-level interface of a condition provider service. Should never be needed for normal apps."</string>
<string name="permlab_bindDreamService" msgid="4776175992848982706">"bind to a dream service"</string>
<string name="permdesc_bindDreamService" msgid="9129615743300572973">"Allows the holder to bind to the top-level interface of a dream service. Should never be needed for normal apps."</string>
- <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"invoke the carrier-provided configuration app"</string>
- <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps."</string>
+ <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"invoke the operator-provided configuration app"</string>
+ <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"Allows the holder to invoke the operator-provided configuration app. Should never be needed for normal apps."</string>
<string name="permlab_accessNetworkConditions" msgid="1270732533356286514">"listen for observations on network conditions"</string>
<string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"Allows an application to listen for observations on network conditions. Should never be needed for normal apps."</string>
<string name="permlab_setInputCalibration" msgid="932069700285223434">"change input device calibration"</string>
@@ -712,8 +712,8 @@
<string name="permdesc_handoverStatus" msgid="3842269451732571070">"Allows this application to receive information about current Android Beam transfers"</string>
<string name="permlab_removeDrmCertificates" msgid="710576248717404416">"remove DRM certificates"</string>
<string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"Allows an application to remove DRM certficates. Should never be needed for normal apps."</string>
- <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"bind to a carrier messaging service"</string>
- <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Allows the holder to bind to the top-level interface of a carrier messaging service. Should never be needed for normal apps."</string>
+ <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"bind to an operator messaging service"</string>
+ <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Allows the holder to bind to the top-level interface of an operator messaging service. Should never be needed for normal apps."</string>
<string name="permlab_bindCarrierServices" msgid="2395596978626237474">"bind to operator services"</string>
<string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"Allows the holder to bind to operator services. Should never be needed for normal apps."</string>
<string name="permlab_access_notification_policy" msgid="5524112842876975537">"access Do Not Disturb"</string>
@@ -1655,7 +1655,7 @@
<string name="kg_sim_pin_instructions" msgid="6479401489471690359">"Enter SIM PIN"</string>
<string name="kg_pin_instructions" msgid="7355933174673539021">"Enter PIN"</string>
<string name="kg_password_instructions" msgid="7179782578809398050">"Enter Password"</string>
- <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"SIM is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_pin_hint" msgid="8190982314659429770">"Enter desired PIN code"</string>
<string name="kg_enter_confirm_pin_hint" msgid="6372557107414074580">"Confirm desired PIN code"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8871937892678885545">"Unlocking SIM card…"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 01d8b39..e1e8187 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -700,8 +700,8 @@
<string name="permdesc_bindConditionProviderService" msgid="6106018791256120258">"Allows the holder to bind to the top-level interface of a condition provider service. Should never be needed for normal apps."</string>
<string name="permlab_bindDreamService" msgid="4776175992848982706">"bind to a dream service"</string>
<string name="permdesc_bindDreamService" msgid="9129615743300572973">"Allows the holder to bind to the top-level interface of a dream service. Should never be needed for normal apps."</string>
- <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"invoke the carrier-provided configuration app"</string>
- <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps."</string>
+ <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"invoke the operator-provided configuration app"</string>
+ <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"Allows the holder to invoke the operator-provided configuration app. Should never be needed for normal apps."</string>
<string name="permlab_accessNetworkConditions" msgid="1270732533356286514">"listen for observations on network conditions"</string>
<string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"Allows an application to listen for observations on network conditions. Should never be needed for normal apps."</string>
<string name="permlab_setInputCalibration" msgid="932069700285223434">"change input device calibration"</string>
@@ -712,8 +712,8 @@
<string name="permdesc_handoverStatus" msgid="3842269451732571070">"Allows this application to receive information about current Android Beam transfers"</string>
<string name="permlab_removeDrmCertificates" msgid="710576248717404416">"remove DRM certificates"</string>
<string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"Allows an application to remove DRM certficates. Should never be needed for normal apps."</string>
- <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"bind to a carrier messaging service"</string>
- <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Allows the holder to bind to the top-level interface of a carrier messaging service. Should never be needed for normal apps."</string>
+ <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"bind to an operator messaging service"</string>
+ <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Allows the holder to bind to the top-level interface of an operator messaging service. Should never be needed for normal apps."</string>
<string name="permlab_bindCarrierServices" msgid="2395596978626237474">"bind to operator services"</string>
<string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"Allows the holder to bind to operator services. Should never be needed for normal apps."</string>
<string name="permlab_access_notification_policy" msgid="5524112842876975537">"access Do Not Disturb"</string>
@@ -1655,7 +1655,7 @@
<string name="kg_sim_pin_instructions" msgid="6479401489471690359">"Enter SIM PIN"</string>
<string name="kg_pin_instructions" msgid="7355933174673539021">"Enter PIN"</string>
<string name="kg_password_instructions" msgid="7179782578809398050">"Enter Password"</string>
- <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"SIM is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_pin_hint" msgid="8190982314659429770">"Enter desired PIN code"</string>
<string name="kg_enter_confirm_pin_hint" msgid="6372557107414074580">"Confirm desired PIN code"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8871937892678885545">"Unlocking SIM card…"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 3ed0279..892041c 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -700,8 +700,8 @@
<string name="permdesc_bindConditionProviderService" msgid="6106018791256120258">"Allows the holder to bind to the top-level interface of a condition provider service. Should never be needed for normal apps."</string>
<string name="permlab_bindDreamService" msgid="4776175992848982706">"bind to a dream service"</string>
<string name="permdesc_bindDreamService" msgid="9129615743300572973">"Allows the holder to bind to the top-level interface of a dream service. Should never be needed for normal apps."</string>
- <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"invoke the carrier-provided configuration app"</string>
- <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps."</string>
+ <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"invoke the operator-provided configuration app"</string>
+ <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"Allows the holder to invoke the operator-provided configuration app. Should never be needed for normal apps."</string>
<string name="permlab_accessNetworkConditions" msgid="1270732533356286514">"listen for observations on network conditions"</string>
<string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"Allows an application to listen for observations on network conditions. Should never be needed for normal apps."</string>
<string name="permlab_setInputCalibration" msgid="932069700285223434">"change input device calibration"</string>
@@ -712,8 +712,8 @@
<string name="permdesc_handoverStatus" msgid="3842269451732571070">"Allows this application to receive information about current Android Beam transfers"</string>
<string name="permlab_removeDrmCertificates" msgid="710576248717404416">"remove DRM certificates"</string>
<string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"Allows an application to remove DRM certficates. Should never be needed for normal apps."</string>
- <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"bind to a carrier messaging service"</string>
- <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Allows the holder to bind to the top-level interface of a carrier messaging service. Should never be needed for normal apps."</string>
+ <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"bind to an operator messaging service"</string>
+ <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Allows the holder to bind to the top-level interface of an operator messaging service. Should never be needed for normal apps."</string>
<string name="permlab_bindCarrierServices" msgid="2395596978626237474">"bind to operator services"</string>
<string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"Allows the holder to bind to operator services. Should never be needed for normal apps."</string>
<string name="permlab_access_notification_policy" msgid="5524112842876975537">"access Do Not Disturb"</string>
@@ -1655,7 +1655,7 @@
<string name="kg_sim_pin_instructions" msgid="6479401489471690359">"Enter SIM PIN"</string>
<string name="kg_pin_instructions" msgid="7355933174673539021">"Enter PIN"</string>
<string name="kg_password_instructions" msgid="7179782578809398050">"Enter Password"</string>
- <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"SIM is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_pin_hint" msgid="8190982314659429770">"Enter desired PIN code"</string>
<string name="kg_enter_confirm_pin_hint" msgid="6372557107414074580">"Confirm desired PIN code"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8871937892678885545">"Unlocking SIM card…"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 8c465f1..9a07025 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -244,7 +244,7 @@
<string name="global_actions" product="default" msgid="6410072189971495460">"Opciones del teléfono"</string>
<string name="global_action_lock" msgid="6949357274257655383">"Bloqueo de pantalla"</string>
<string name="global_action_power_off" msgid="4404936470711393203">"Apagar"</string>
- <string name="global_action_power_options" msgid="1185286119330160073">"Encender o apagar"</string>
+ <string name="global_action_power_options" msgid="1185286119330160073">"Apagar o reiniciar"</string>
<string name="global_action_restart" msgid="4678451019561687074">"Reiniciar"</string>
<string name="global_action_emergency" msgid="1387617624177105088">"Emergencia"</string>
<string name="global_action_bug_report" msgid="5127867163044170003">"Informe de errores"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 5add36b..e473ab6 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -34,7 +34,7 @@
<string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
<string name="mmiError" msgid="2862759606579822246">"કનેક્શન સમસ્યા અથવા અમાન્ય MMI કોડ."</string>
<string name="mmiFdnError" msgid="3975490266767565852">"ઑપરેશન ફક્ત સ્થિર ડાયલિંગ નંબર્સ પર પ્રતિબંધિત છે."</string>
- <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"તમે રોમિંગમાં હોવ તે વખતે તમારા ફોન પરથી કૉલ ફોરવર્ડિગ સેટિંગ્સ બદલી શકતાં નથી."</string>
+ <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"તમે રોમિંગમાં હો તે વખતે તમારા ફોન પરથી કૉલ ફૉરવર્ડિગ સેટિંગ બદલી શકતાં નથી."</string>
<string name="serviceEnabled" msgid="7549025003394765639">"સેવા સક્ષમ હતી."</string>
<string name="serviceEnabledFor" msgid="1463104778656711613">"સેવા આ માટે સક્ષમ હતી:"</string>
<string name="serviceDisabled" msgid="641878791205871379">"સેવા અક્ષમ કરવામાં આવી છે."</string>
@@ -124,7 +124,7 @@
<string name="roamingTextSearching" msgid="5323235489657753486">"સેવા શોધી રહ્યું છે"</string>
<string name="wfcRegErrorTitle" msgid="3193072971584858020">"વાઇ-ફાઇ કૉલિંગ સેટ કરી શકાયું નથી"</string>
<string-array name="wfcOperatorErrorAlertMessages">
- <item msgid="468830943567116703">"વાઇ-ફાઇ પરથી કૉલ કરવા અને સંદેશા મોકલવા માટે પહેલાં તમારા કૅરિઅરને આ સેવા સેટ કરવા માટે કહો. પછી સેટિંગ્સમાંથી વાઇ-ફાઇ કૉલિંગ ફરીથી ચાલુ કરો. (ભૂલ કોડ: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
+ <item msgid="468830943567116703">"વાઇ-ફાઇ પરથી કૉલ કરવા અને સંદેશા મોકલવા માટે પહેલાં તમારા કૅરિઅરને આ સેવા સેટ કરવા માટે કહો. પછી સેટિંગમાંથી વાઇ-ફાઇ કૉલિંગ ફરીથી ચાલુ કરો. (ભૂલ કોડ: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
</string-array>
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="4795145070505729156">"તમારા કૅરિઅરમાં વાઇ-ફાઇ કૉલિંગ રજિસ્ટર કરવામાં સમસ્યા આવી: <xliff:g id="CODE">%1$s</xliff:g>"</item>
@@ -401,7 +401,7 @@
<string name="permlab_getPackageSize" msgid="375391550792886641">"ઍપ્લિકેશન સંગ્રહ સ્થાન માપો"</string>
<string name="permdesc_getPackageSize" msgid="742743530909966782">"એપ્લિકેશનને તેનો કોડ, ડેટા અને કેશ કદ પુનઃપ્રાપ્ત કરવાની મંજૂરી આપે છે."</string>
<string name="permlab_writeSettings" msgid="8057285063719277394">"સિસ્ટમ સેટિંગમાં ફેરફાર કરો"</string>
- <string name="permdesc_writeSettings" msgid="8293047411196067188">"એપ્લિકેશનને તમારા સિસ્ટમના સેટિંગ્સ ડેટાને સંશોધિત કરવાની મંજૂરી આપે છે. દુર્ભાવનાપૂર્ણ ઍપ્લિકેશનો તમારા સિસ્ટમની ગોઠવણીને દૂષિત કરી શકે છે."</string>
+ <string name="permdesc_writeSettings" msgid="8293047411196067188">"ઍપને તમારા સિસ્ટમના સેટિંગ ડેટાને સંશોધિત કરવાની મંજૂરી આપે છે. દુર્ભાવનાપૂર્ણ ઍપ તમારા સિસ્ટમની ગોઠવણીને દૂષિત કરી શકે છે."</string>
<string name="permlab_receiveBootCompleted" msgid="6643339400247325379">"સ્ટાર્ટઅપ પર શરૂ કરો"</string>
<string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"એપ્લિકેશનને સિસ્ટમ બૂટ થવાનું સમાપ્ત કરી લે કે તરત જ પોતાની જાતે પ્રારંભ થવાની મંજૂરી આપે છે. આનાથી ટેબ્લેટને પ્રારંભ થવામાં વધુ લાંબો સમય લાગી શકે છે અને એપ્લિકેશનને હંમેશા ચાલુ રહીને ટેબ્લેટને એકંદર ધીમું કરવાની મંજૂરી આપી શકે છે."</string>
<string name="permdesc_receiveBootCompleted" product="tv" msgid="4900842256047614307">"ઍપને સિસ્ટમ બૂટ થવાનું સમાપ્ત કરી લે કે તરત જ પોતાની જાતે પ્રારંભ થવાની મંજૂરી આપે છે. આનાથી તમારા Android TV ડિવાઇસને શરૂ થવામાં વધુ સમય લાગી શકે છે અને ઍપને હંમેશાં ચાલુ રહીને ડિવાઇસને એકંદર ધીમું કરવાની મંજૂરી આપે છે."</string>
@@ -442,8 +442,8 @@
<string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"ઍપ ઉપયોગમાં હોય તે વખતે સ્થાન સેવાઓમાંથી આ ઍપ તમારું અંદાજિત સ્થાન મેળવી શકે છે. ઍપ સ્થાન મેળવી શકે તે માટે તમારા ડિવાઇસમાં સ્થાન સેવાઓ ચાલુ કરેલી હોવી જરૂરી છે."</string>
<string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"બૅકગ્રાઉન્ડમાં સ્થાન ઍક્સેસ કરો"</string>
<string name="permdesc_accessBackgroundLocation" msgid="8264885066095638105">"આ ઍપ કોઈપણ સમયે સ્થાનને ઍક્સેસ કરી શકે છે, પછી ભલેને આ ઍપ ઉપયોગમાં ન હોય."</string>
- <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"તમારી ઑડિઓ સેટિંગ્સ બદલો"</string>
- <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"એપ્લિકેશનને વૈશ્વિક ઑડિઓ સેટિંગ્સને સંશોધિત કરવાની મંજૂરી આપે છે, જેમ કે વૉલ્યૂમ અને આઉટપુટ માટે કયા સ્પીકરનો ઉપયોગ કરવો."</string>
+ <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"તમારા ઑડિયો સેટિંગ બદલો"</string>
+ <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"ઍપને વૈશ્વિક ઑડિયો સેટિંગમાં ફેરફાર કરવાની મંજૂરી આપે છે, જેમ કે વૉલ્યૂમ અને આઉટપુટ માટે કયા સ્પીકરનો ઉપયોગ કરવો."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ઑડિઓ રેકોર્ડ કરવાની"</string>
<string name="permdesc_recordAudio" msgid="5857246765327514062">"આ ઍપ ઉપયોગમાં હોય ત્યારે તે માઇક્રોફોનનો ઉપયોગ કરીને ઑડિયો રેકોર્ડ કરી શકે છે."</string>
<string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"બૅકગ્રાઉન્ડમાં ઑડિયો રેકોર્ડ કરો"</string>
@@ -519,7 +519,7 @@
<string name="permdesc_changeWifiMulticastState" product="tablet" msgid="191079868596433554">"એપ્લિકેશનને ફક્ત તમારા ટેબ્લેટ પર નહીં, પણ મલ્ટિકાસ્ટ સરનામાંનો ઉપયોગ કરીને વાઇ-ફાઇ નેટવર્ક પરના તમામ ઉપકરણોને મોકલાયેલ પૅકેટ્સ પ્રાપ્ત કરવાની મંજૂરી આપે છે. તે બિન-મલ્ટિકાસ્ટ મોડ કરતાં વધુ પાવર વાપરે છે."</string>
<string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"ઍપને ફક્ત તમારા Android TV ડિવાઇસ પર નહીં, પણ મલ્ટિકાસ્ટ ઍડ્રેસનો ઉપયોગ કરીને વાઇ-ફાઇ નેટવર્ક પરના તમામ ડિવાઇસને મોકલાયેલા પૅકેટ પ્રાપ્ત કરવાની મંજૂરી આપે છે. તે બિન-મલ્ટિકાસ્ટ મોડ કરતાં વધુ પાવર વાપરે છે."</string>
<string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"એપ્લિકેશનને ફક્ત તમારા ફોન પર નહીં, પણ મલ્ટિકાસ્ટ સરનામાંનો ઉપયોગ કરીને વાઇ-ફાઇ નેટવર્ક પર તમામ ઉપકરણોને મોકલાયેલ પૅકેટ્સ પ્રાપ્ત કરવાની મંજૂરી આપે છે. તે બિન-મલ્ટિકાસ્ટ મોડ કરતાં વધુ પાવર વાપરે છે."</string>
- <string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"બ્લૂટૂથ સેટિંગ્સ ઍક્સેસ કરો"</string>
+ <string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"બ્લૂટૂથ સેટિંગ ઍક્સેસ કરો"</string>
<string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"એપ્લિકેશનને સ્થાનિક બ્લૂટૂથ ટેબ્લેટ ગોઠવવાની અને રિમોટ ઉપકરણો શોધવા અને તેમની સાથે જોડી કરવાની મંજૂરી આપે છે."</string>
<string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"ઍપને તમારા Android TV ડિવાઇસ પર બ્લૂટૂથને ગોઠવવાની અને રિમોટ ડિવાઇસ શોધવા અને તેમની સાથે જોડાણ કરવાની મંજૂરી આપે છે."</string>
<string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"એપ્લિકેશનને સ્થાનિક બ્લૂટૂથ ફોન ગોઠવવાની અને રિમોટ ઉપકરણો શોધવા અને તેમની સાથે જોડી કરવાની મંજૂરી આપે છે."</string>
@@ -662,10 +662,10 @@
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"ચહેરા આઇકન"</string>
- <string name="permlab_readSyncSettings" msgid="6250532864893156277">"સમન્વયન સેટિંગ્સ વાંચો"</string>
- <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ઍપ્લિકેશનને એકાઉન્ટ માટે સમન્વયન સેટિંગ્સને વાંચવાની મંજૂરી આપે છે. ઉદાહરણ તરીકે, આ એકાઉન્ટ સાથે લોકો ઍપ્લિકેશન સમન્વયિત થઈ છે કે કેમ તે નિર્ધારિત કરી શકે છે."</string>
+ <string name="permlab_readSyncSettings" msgid="6250532864893156277">"સિંક સેટિંગ વાંચો"</string>
+ <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ઍપને એકાઉન્ટ માટે સિંક સેટિંગને વાંચવાની મંજૂરી આપે છે. ઉદાહરણ તરીકે, આ એકાઉન્ટ સાથે લોકો ઍપ સિંક થઈ છે કે કેમ તે નિર્ધારિત કરી શકે છે."</string>
<string name="permlab_writeSyncSettings" msgid="6583154300780427399">"સમન્વયન ચાલુ અને બંધ ટોગલ કરો"</string>
- <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"એપ્લિકેશનને એકાઉન્ટ માટે સમન્વયન સેટિંગ્સ સંશોધિત કરવાની મંજૂરી આપે છે. ઉદાહરણ તરીકે, આનો ઉપયોગ એકાઉન્ટ સાથે લોકો એપ્લિકેશનના સમન્વયનને સક્ષમ કરવા માટે થઈ શકે છે."</string>
+ <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"ઍપને એકાઉન્ટ માટે સિંક સેટિંગમાં ફેરફાર કરવાની મંજૂરી આપે છે. ઉદાહરણ તરીકે, આનો ઉપયોગ એકાઉન્ટ સાથે લોકો ઍપના સિંકને ચાલુ કરવા માટે થઈ શકે છે."</string>
<string name="permlab_readSyncStats" msgid="3747407238320105332">"સમન્વયન આંકડા વાંચો"</string>
<string name="permdesc_readSyncStats" msgid="3867809926567379434">"એપ્લિકેશનને સમન્વયન ઇવેન્ટ્સનો ઇતિહાસ અને કેટલો ડેટા સમન્વયિત થયો છે તે સહિત કોઈ એકાઉન્ટ માટેનાં સમન્વયન આંકડા વાંચવાની મંજૂરી આપે છે."</string>
<string name="permlab_sdcardRead" msgid="5791467020950064920">"તમારા શેર કરેલા સ્ટોરેજના કન્ટેન્ટને વાંચો"</string>
@@ -1210,7 +1210,7 @@
<string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"છબી કૅપ્ચર કરો"</string>
<string name="alwaysUse" msgid="3153558199076112903">"આ ક્રિયા માટે ડિફોલ્ટ તરીકે ઉપયોગમાં લો."</string>
<string name="use_a_different_app" msgid="4987790276170972776">"અલગ એપ્લિકેશનનો ઉપયોગ કરો"</string>
- <string name="clearDefaultHintMsg" msgid="1325866337702524936">"સિસ્ટમ સેટિંગ્સ > ઍપ્લિકેશનો > ડાઉનલોડ કરેલમાં ડિફોલ્ટ સાફ કરો."</string>
+ <string name="clearDefaultHintMsg" msgid="1325866337702524936">"સિસ્ટમ સેટિંગ > ઍપ > ડાઉનલોડ કરેલામાં ડિફૉલ્ટ સાફ કરો."</string>
<string name="chooseActivity" msgid="8563390197659779956">"એક ક્રિયા પસંદ કરો"</string>
<string name="chooseUsbActivity" msgid="2096269989990986612">"USB ઉપકરણ માટે ઍપ્લિકેશન પસંદ કરો"</string>
<string name="noApplications" msgid="1186909265235544019">"કોઈ ઍપ્લિકેશન આ ક્રિયા કરી શકતી નથી."</string>
@@ -1238,8 +1238,8 @@
<string name="launch_warning_original" msgid="3332206576800169626">"<xliff:g id="APP_NAME">%1$s</xliff:g> મૂળરૂપે લોંચ થઈ હતી."</string>
<string name="screen_compat_mode_scale" msgid="8627359598437527726">"સ્કેલ"</string>
<string name="screen_compat_mode_show" msgid="5080361367584709857">"હંમેશા બતાવો"</string>
- <string name="screen_compat_mode_hint" msgid="4032272159093750908">"આને સિસ્ટમ સેટિંગ્સ > ઍપ્લિકેશનો > ડાઉનલોડ કરેલમાં ફરીથી સક્ષમ કરો."</string>
- <string name="unsupported_display_size_message" msgid="7265211375269394699">"<xliff:g id="APP_NAME">%1$s</xliff:g> વર્તમાન પ્રદર્શન કદની સેટિંગનું સમર્થન કરતું નથી અને અનપેક્ષિત રીતે વર્તી શકે છે."</string>
+ <string name="screen_compat_mode_hint" msgid="4032272159093750908">"આને સિસ્ટમ સેટિંગ > ઍપ > ડાઉનલોડ કરેલામાં ફરીથી ચાલુ કરો."</string>
+ <string name="unsupported_display_size_message" msgid="7265211375269394699">"<xliff:g id="APP_NAME">%1$s</xliff:g> વર્તમાન ડિસ્પ્લે કદની સેટિંગને સપોર્ટ કરતું નથી અને અનપેક્ષિત રીતે વર્તી શકે છે."</string>
<string name="unsupported_display_size_show" msgid="980129850974919375">"હંમેશાં બતાવો"</string>
<string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"<xliff:g id="APP_NAME">%1$s</xliff:g>ને Android OSના અસંગત વર્ઝન માટે બનાવવામાં આવ્યું હતું અને તે અનપેક્ષિત રીતે કાર્ય કરી શકે છે. ઍપનું અપડેટ કરેલ વર્ઝન ઉપલબ્ધ હોઈ શકે છે."</string>
<string name="unsupported_compile_sdk_show" msgid="1601210057960312248">"હંમેશાં બતાવો"</string>
@@ -1335,7 +1335,7 @@
<string name="sms_short_code_confirm_allow" msgid="920477594325526691">"મોકલો"</string>
<string name="sms_short_code_confirm_deny" msgid="1356917469323768230">"રદ કરો"</string>
<string name="sms_short_code_remember_choice" msgid="1374526438647744862">"મારી પસંદગી યાદ રાખો"</string>
- <string name="sms_short_code_remember_undo_instruction" msgid="2620984439143080410">"તમે પછીથી આને સેટિંગ્સ > એપ્લિકેશન્સમાં બદલી શકો છો"</string>
+ <string name="sms_short_code_remember_undo_instruction" msgid="2620984439143080410">"તમે પછીથી આને સેટિંગ > ઍપમાં બદલી શકો છો"</string>
<string name="sms_short_code_confirm_always_allow" msgid="2223014893129755950">"હંમેશા મંજૂરી આપો"</string>
<string name="sms_short_code_confirm_never_allow" msgid="2688828813521652079">"ક્યારેય મંજૂરી આપશો નહીં"</string>
<string name="sim_removed_title" msgid="5387212933992546283">"સિમ કાર્ડ કાઢી નાખ્યો"</string>
@@ -1502,7 +1502,7 @@
<string name="vpn_lockdown_connected" msgid="2853127976590658469">"હંમેશા-ચાલુ VPN કનેક્ટ થયું"</string>
<string name="vpn_lockdown_disconnected" msgid="5573611651300764955">"હંમેશાં-ચાલુ VPN થી ડિસ્કનેક્ટ થયું"</string>
<string name="vpn_lockdown_error" msgid="4453048646854247947">"હંમેશાં-ચાલુ VPN સાથે કનેક્ટ કરી શકાયું નથી"</string>
- <string name="vpn_lockdown_config" msgid="8331697329868252169">"નેટવર્ક અથવા VPN સેટિંગ્સ બદલો"</string>
+ <string name="vpn_lockdown_config" msgid="8331697329868252169">"નેટવર્ક અથવા VPN સેટિંગ બદલો"</string>
<string name="upload_file" msgid="8651942222301634271">"ફાઇલ પસંદ કરો"</string>
<string name="no_file_chosen" msgid="4146295695162318057">"કોઈ ફાઇલ પસંદ કરેલી નથી"</string>
<string name="reset" msgid="3865826612628171429">"ફરીથી સેટ કરો"</string>
@@ -1616,7 +1616,7 @@
<string name="SetupCallDefault" msgid="5581740063237175247">"કૉલ સ્વીકારીએ?"</string>
<string name="activity_resolver_use_always" msgid="5575222334666843269">"હંમેશાં"</string>
<string name="activity_resolver_use_once" msgid="948462794469672658">"ફક્ત એક વાર"</string>
- <string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s કાર્ય પ્રોફાઇલનું સમર્થન કરતું નથી"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s ઑફિસની પ્રોફાઇલને સપોર્ટ કરતું નથી"</string>
<string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"ટેબ્લેટ"</string>
<string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ફોન"</string>
@@ -2067,7 +2067,7 @@
<string name="popup_window_default_title" msgid="6907717596694826919">"પૉપઅપ વિંડો"</string>
<string name="slice_more_content" msgid="3377367737876888459">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="9206301954024286063">"આ ઍપનું વર્ઝન ડાઉનગ્રેડ કરવામાં આવ્યું છે અથવા આ શૉર્ટકટ સાથે સુસંગત નથી"</string>
- <string name="shortcut_restore_not_supported" msgid="4763198938588468400">"શૉર્ટકટ ફરી મેળવી શકાયો નથી કારણ કે ઍપ બૅકઅપ અને ફરી મેળવવાનું સમર્થન કરતી નથી"</string>
+ <string name="shortcut_restore_not_supported" msgid="4763198938588468400">"શૉર્ટકટ ફરી મેળવી શકાયો નથી કારણ કે ઍપ બૅકઅપ અને ફરી મેળવવાને સપોર્ટ કરતી નથી"</string>
<string name="shortcut_restore_signature_mismatch" msgid="579345304221605479">"શૉર્ટકટ ફરી મેળવી શકાયો નથી કારણ કે ઍપમાં છે તે સહી મેળ ખાતી નથી"</string>
<string name="shortcut_restore_unknown_issue" msgid="2478146134395982154">"શૉર્ટકટ પાછો મેળવી શકાયો નથી"</string>
<string name="shortcut_disabled_reason_unknown" msgid="753074793553599166">"શૉર્ટકટને બંધ કરવામાં આવ્યો છે"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 12f8cd4..6da4072 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1951,7 +1951,7 @@
<string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string>
<string name="call_notification_answer_action" msgid="5999246836247132937">"जवाफ दिनुहोस्"</string>
<string name="call_notification_answer_video_action" msgid="2086030940195382249">"भिडियो"</string>
- <string name="call_notification_decline_action" msgid="3700345945214000726">"अस्वीकार गर्नुहोस्"</string>
+ <string name="call_notification_decline_action" msgid="3700345945214000726">"काट्नुहोस्"</string>
<string name="call_notification_hang_up_action" msgid="9130720590159188131">"फोन राख्नुहोस्"</string>
<string name="call_notification_incoming_text" msgid="6143109825406638201">"आगमन कल"</string>
<string name="call_notification_ongoing_text" msgid="3880832933933020875">"भइरहेको कल"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 93f2d742..d632e0c 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -434,7 +434,7 @@
<string name="permdesc_bodySensors" product="default" msgid="2365357960407973997">"Aplikaciji omogoča dostop do podatkov tipal, ki nadzirajo vaše fizično stanje, med drugim vaš srčni utrip."</string>
<string name="permlab_readCalendar" msgid="6408654259475396200">"Branje dogodkov v koledarjih in podrobnosti koledarjev"</string>
<string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"Ta aplikacija lahko prebere vse dogodke v koledarju, ki so shranjeni v tabličnem računalniku, ter shrani podatke koledarja ali jih deli z drugimi."</string>
- <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"Ta aplikacija lahko prebere vse dogodke v koledarju, ki so shranjeni v napravi Android TV, ter shrani podatke koledarja ali jih da v skupno rabo z drugimi."</string>
+ <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"Ta aplikacija lahko prebere vse dogodke v koledarju, ki so shranjeni v napravi Android TV, ter shrani podatke koledarja ali jih deli z drugimi."</string>
<string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"Ta aplikacija lahko prebere vse dogodke v koledarju, ki so shranjeni v telefonu, ter shrani podatke koledarja ali jih deli z drugimi."</string>
<string name="permlab_writeCalendar" msgid="6422137308329578076">"dodajanje ali spreminjanje dogodkov v koledarju in pošiljanje e-pošte gostom brez vedenja lastnikov"</string>
<string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"Ta aplikacija lahko dodaja, odstranjuje in spreminja dogodke v koledarju, ki so shranjeni v tabličnem računalniku. Ta aplikacija lahko pošilja sporočila, ki bodo morda videti, kot da prihajajo od lastnikov koledarjev, ali spreminja dogodke brez vednosti lastnikov."</string>
@@ -932,7 +932,7 @@
<string name="lockscreen_forgot_pattern_button_text" msgid="8362442730606839031">"Ali ste pozabili vzorec?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"Odklepanje računa"</string>
<string name="lockscreen_glogin_too_many_attempts" msgid="3775904917743034195">"Preveč poskusov vzorca"</string>
- <string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"Če želite odkleniti telefon, se prijavite z Google Računom."</string>
+ <string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"Če želite odkleniti telefon, se prijavite z računom Google."</string>
<string name="lockscreen_glogin_username_hint" msgid="6916101478673157045">"Uporabniško ime (e-pošta)"</string>
<string name="lockscreen_glogin_password_hint" msgid="3031027901286812848">"Geslo"</string>
<string name="lockscreen_glogin_submit_button" msgid="3590556636347843733">"Prijava"</string>
@@ -1237,8 +1237,8 @@
<string name="whichEditApplicationNamed" msgid="8096494987978521514">"Urejanje z aplikacijo %1$s"</string>
<string name="whichEditApplicationLabel" msgid="1463288652070140285">"Urejanje"</string>
<string name="whichSendApplication" msgid="4143847974460792029">"Deljenje z drugimi"</string>
- <string name="whichSendApplicationNamed" msgid="4470386782693183461">"Skupna raba z aplikacijo %1$s"</string>
- <string name="whichSendApplicationLabel" msgid="7467813004769188515">"Skupna raba"</string>
+ <string name="whichSendApplicationNamed" msgid="4470386782693183461">"Deljenje z aplikacijo %1$s"</string>
+ <string name="whichSendApplicationLabel" msgid="7467813004769188515">"Deljenje"</string>
<string name="whichSendToApplication" msgid="77101541959464018">"Pošiljanje z aplikacijo"</string>
<string name="whichSendToApplicationNamed" msgid="3385686512014670003">"Pošiljanje z aplikacijo %1$s"</string>
<string name="whichSendToApplicationLabel" msgid="3543240188816513303">"Pošiljanje"</string>
@@ -1400,14 +1400,14 @@
<string name="perm_costs_money" msgid="749054595022779685">"to je lahko plačljivo"</string>
<string name="dlg_ok" msgid="5103447663504839312">"V redu"</string>
<string name="usb_charging_notification_title" msgid="1674124518282666955">"Polnjenje naprave prek USB-ja"</string>
- <string name="usb_supplying_notification_title" msgid="5378546632408101811">"Polnjenje akumulatorja v povezani napravi prek USB-ja"</string>
+ <string name="usb_supplying_notification_title" msgid="5378546632408101811">"Polnjenje baterije v povezani napravi prek USB-ja"</string>
<string name="usb_mtp_notification_title" msgid="1065989144124499810">"Vklopljen je prenos datotek prek USB-ja"</string>
<string name="usb_ptp_notification_title" msgid="5043437571863443281">"Vklopljen je način PTP prek USB-ja"</string>
<string name="usb_tether_notification_title" msgid="8828527870612663771">"Vklopljen je internet prek USB-ja"</string>
<string name="usb_midi_notification_title" msgid="7404506788950595557">"Vklopljen je način MIDI prek USB-ja"</string>
<string name="usb_accessory_notification_title" msgid="1385394660861956980">"Dodatek USB je priključen"</string>
<string name="usb_notification_message" msgid="4715163067192110676">"Dotaknite se za več možnosti."</string>
- <string name="usb_power_notification_message" msgid="7284765627437897702">"Polnjenje akumulatorja v povezani napravi. Dotaknite se za več možnosti."</string>
+ <string name="usb_power_notification_message" msgid="7284765627437897702">"Polnjenje baterije v povezani napravi. Dotaknite se za več možnosti."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Zaznana je analogna dodatna zvočna oprema"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Priključena naprava ni združljiva s tem telefonom. Dotaknite se za več informacij."</string>
<string name="adb_active_notification_title" msgid="408390247354560331">"Iskanje napak prek USB-ja je povezano"</string>
@@ -1427,8 +1427,8 @@
<string name="taking_remote_bugreport_notification_title" msgid="1582531382166919850">"Zajemanje poročila o napakah …"</string>
<string name="share_remote_bugreport_notification_title" msgid="6708897723753334999">"Želite poslati poročilo o napakah?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="3077385149217638550">"Pošiljanje poročila o napakah …"</string>
- <string name="share_remote_bugreport_notification_message_finished" msgid="7325635795739260135">"Skrbnik je zahteval poročilo o napakah za pomoč pri odpravljanju napak v tej napravi. Aplikacije in podatki bodo morda dani v skupno rabo."</string>
- <string name="share_remote_bugreport_action" msgid="7630880678785123682">"SKUPNA RABA"</string>
+ <string name="share_remote_bugreport_notification_message_finished" msgid="7325635795739260135">"Skrbnik je zahteval poročilo o napakah za pomoč pri odpravljanju napak v tej napravi. Aplikacije in podatki bodo morda deljeni."</string>
+ <string name="share_remote_bugreport_action" msgid="7630880678785123682">"DELJENJE"</string>
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"NE SPREJMEM"</string>
<string name="select_input_method" msgid="3971267998568587025">"Izberite način vnosa"</string>
<string name="show_ime" msgid="6406112007347443383">"Ohrani na zaslonu, dokler je aktivna fizična tipkovnica"</string>
@@ -1616,7 +1616,7 @@
<string name="action_menu_overflow_description" msgid="4579536843510088170">"Več možnosti"</string>
<string name="action_bar_home_description_format" msgid="5087107531331621803">"%1$s, %2$s"</string>
<string name="action_bar_home_subtitle_description_format" msgid="4346835454749569826">"%1$s, %2$s, %3$s"</string>
- <string name="storage_internal" msgid="8490227947584914460">"Notranja shramba v skupni rabi"</string>
+ <string name="storage_internal" msgid="8490227947584914460">"Notranja deljena shramba"</string>
<string name="storage_sd_card" msgid="3404740277075331881">"Kartica SD"</string>
<string name="storage_sd_card_label" msgid="7526153141147470509">"Kartica SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb_drive" msgid="448030813201444573">"Pogon USB"</string>
@@ -1709,7 +1709,7 @@
<string name="kg_invalid_puk" msgid="4809502818518963344">"Vnovič vnesite pravilno kodo PUK. Večkratni poskusi bodo trajno onemogočili kartico SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="4705368340409816254">"Kodi PIN se ne ujemata"</string>
<string name="kg_login_too_many_attempts" msgid="699292728290654121">"Preveč poskusov vzorca"</string>
- <string name="kg_login_instructions" msgid="3619844310339066827">"Če želite odkleniti napravo, se prijavite z Google Računom."</string>
+ <string name="kg_login_instructions" msgid="3619844310339066827">"Če želite odkleniti napravo, se prijavite z računom Google."</string>
<string name="kg_login_username_hint" msgid="1765453775467133251">"Uporabniško ime (e-pošta)"</string>
<string name="kg_login_password_hint" msgid="3330530727273164402">"Geslo"</string>
<string name="kg_login_submit_button" msgid="893611277617096870">"Prijava"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 25e2820..239c9f8 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1197,7 +1197,7 @@
<string name="whichEditApplicationNamed" msgid="8096494987978521514">"Redakto me %1$s"</string>
<string name="whichEditApplicationLabel" msgid="1463288652070140285">"Redakto"</string>
<string name="whichSendApplication" msgid="4143847974460792029">"Ndaj"</string>
- <string name="whichSendApplicationNamed" msgid="4470386782693183461">"Shpërnda publikisht me %1$s"</string>
+ <string name="whichSendApplicationNamed" msgid="4470386782693183461">"Shpërndaj me %1$s"</string>
<string name="whichSendApplicationLabel" msgid="7467813004769188515">"Ndaj"</string>
<string name="whichSendToApplication" msgid="77101541959464018">"Dërgo me"</string>
<string name="whichSendToApplicationNamed" msgid="3385686512014670003">"Dërgo me %1$s"</string>
@@ -1565,8 +1565,8 @@
<string name="keyboardview_keycode_enter" msgid="168054869339091055">"Enter"</string>
<string name="activitychooserview_choose_application" msgid="3500574466367891463">"Zgjidh një aplikacion"</string>
<string name="activitychooserview_choose_application_error" msgid="6937782107559241734">"Nuk mundi ta hapte <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
- <string name="shareactionprovider_share_with" msgid="2753089758467748982">"Shpërnda publikisht me"</string>
- <string name="shareactionprovider_share_with_application" msgid="4902832247173666973">"Shpërnda me <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+ <string name="shareactionprovider_share_with" msgid="2753089758467748982">"Shpërndaj me"</string>
+ <string name="shareactionprovider_share_with_application" msgid="4902832247173666973">"Shpërndaj me <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="982510275422590757">"Dorezë me rrëshqitje. Preke dhe mbaje të shtypur."</string>
<string name="description_target_unlock_tablet" msgid="7431571180065859551">"Rrëshqit për të shkyçur."</string>
<string name="action_bar_home_description" msgid="1501655419158631974">"Orientohu për në shtëpi"</string>
@@ -1610,7 +1610,7 @@
<string name="sha1_fingerprint" msgid="2339915142825390774">"Gjurma e gishtit SHA-1:"</string>
<string name="activity_chooser_view_see_all" msgid="3917045206812726099">"Shikoji të gjitha"</string>
<string name="activity_chooser_view_dialog_title_default" msgid="8880731437191978314">"Zgjidh aktivitetin"</string>
- <string name="share_action_provider_share_with" msgid="1904096863622941880">"Shpërnda publikisht me"</string>
+ <string name="share_action_provider_share_with" msgid="1904096863622941880">"Shpërndaj me"</string>
<string name="sending" msgid="206925243621664438">"Po dërgon…"</string>
<string name="launchBrowserDefault" msgid="6328349989932924119">"Të hapet shfletuesi?"</string>
<string name="SetupCallDefault" msgid="5581740063237175247">"Dëshiron ta pranosh telefonatën?"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index cb0b420..940ee56 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -572,7 +572,7 @@
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentiseringen avbröts"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Identifierades inte"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autentiseringen avbröts"</string>
- <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Pinkod, grafiskt lösenord eller lösenord har inte angetts"</string>
+ <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Pinkod, mönster eller lösenord har inte angetts"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Ett fel uppstod vid autentiseringen"</string>
<string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Använd skärmlåset"</string>
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Fortsätt med hjälp av ditt skärmlås"</string>
@@ -881,7 +881,7 @@
<string name="lockscreen_screen_locked" msgid="7364905540516041817">"Skärmen har låsts."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Tryck på Menu för att låsa upp eller ringa nödsamtal."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Tryck på Menu för att låsa upp."</string>
- <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Rita grafiskt lösenord för att låsa upp"</string>
+ <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Rita mönster för att låsa upp"</string>
<string name="lockscreen_emergency_call" msgid="7549683825868928636">"Nödsamtal"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Tillbaka till samtal"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Korrekt!"</string>
@@ -925,7 +925,7 @@
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6807200118164539589">"Försök igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="8362442730606839031">"Glömt ditt grafiska lösenord?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"Lås upp konto"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="3775904917743034195">"För många försök med grafiskt lösenord"</string>
+ <string name="lockscreen_glogin_too_many_attempts" msgid="3775904917743034195">"För många försök med mönster"</string>
<string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"Logga in med ditt Google-konto om du vill låsa upp."</string>
<string name="lockscreen_glogin_username_hint" msgid="6916101478673157045">"Användarnamn (e-post)"</string>
<string name="lockscreen_glogin_password_hint" msgid="3031027901286812848">"Lösenord"</string>
@@ -936,12 +936,12 @@
<string name="lockscreen_unlock_label" msgid="4648257878373307582">"Lås upp"</string>
<string name="lockscreen_sound_on_label" msgid="1660281470535492430">"Ljud på"</string>
<string name="lockscreen_sound_off_label" msgid="2331496559245450053">"Ljud av"</string>
- <string name="lockscreen_access_pattern_start" msgid="3778502525702613399">"Skriver grafiskt lösenord"</string>
- <string name="lockscreen_access_pattern_cleared" msgid="7493849102641167049">"Grafiskt lösenord har tagits bort"</string>
+ <string name="lockscreen_access_pattern_start" msgid="3778502525702613399">"Ritar mönster"</string>
+ <string name="lockscreen_access_pattern_cleared" msgid="7493849102641167049">"Mönster har tagits bort"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6746676335293144163">"En cell har lagts till"</string>
<string name="lockscreen_access_pattern_cell_added_verbose" msgid="2931364927622563465">"Cell <xliff:g id="CELL_INDEX">%1$s</xliff:g> har lagts till"</string>
- <string name="lockscreen_access_pattern_detected" msgid="3931150554035194012">"Grafiskt lösenord har slutförts"</string>
- <string name="lockscreen_access_pattern_area" msgid="1288780416685002841">"Fält för grafiskt lösenord."</string>
+ <string name="lockscreen_access_pattern_detected" msgid="3931150554035194012">"Mönster har slutförts"</string>
+ <string name="lockscreen_access_pattern_area" msgid="1288780416685002841">"Fält för mönster."</string>
<string name="keyguard_accessibility_widget_changed" msgid="7298011259508200234">"%1$s. Widget %2$d av %3$d."</string>
<string name="keyguard_accessibility_add_widget" msgid="8245795023551343672">"Lägg till en widget."</string>
<string name="keyguard_accessibility_widget_empty_slot" msgid="544239307077644480">"Tom"</string>
@@ -957,13 +957,13 @@
<string name="keyguard_accessibility_widget_deleted" msgid="1509738950119878705">"Widgeten <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> har tagits bort."</string>
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Expandera upplåsningsytan."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Lås upp genom att dra."</string>
- <string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Lås upp med grafiskt lösenord."</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Lås upp med mönster."</string>
<string name="keyguard_accessibility_face_unlock" msgid="4533832120787386728">"Ansiktslås."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Lås upp med PIN-kod."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Lås upp med SIM-kortets pinkod."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Lås upp med SIM-kortets PUK-kod."</string>
<string name="keyguard_accessibility_password_unlock" msgid="6130186108581153265">"Lås upp med lösenord."</string>
- <string name="keyguard_accessibility_pattern_area" msgid="1419570880512350689">"Fält för grafiskt lösenord."</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="1419570880512350689">"Fält för mönster."</string>
<string name="keyguard_accessibility_slide_area" msgid="4331399051142520176">"Fält med dragreglage."</string>
<string name="password_keyboard_label_symbol_key" msgid="2716255580853511949">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="5294837425652726684">"ABC"</string>
@@ -1644,7 +1644,7 @@
<string name="display_manager_overlay_display_title" msgid="1480158037150469170">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="2810034719482834679">", säker"</string>
<string name="kg_forgot_pattern_button_text" msgid="406145459223122537">"Har du glömt ditt grafiska lösenord?"</string>
- <string name="kg_wrong_pattern" msgid="1342812634464179931">"Fel grafiskt lösenord"</string>
+ <string name="kg_wrong_pattern" msgid="1342812634464179931">"Fel mönster"</string>
<string name="kg_wrong_password" msgid="2384677900494439426">"Fel lösenord"</string>
<string name="kg_wrong_pin" msgid="3680925703673166482">"Fel PIN-kod"</string>
<plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="236717428673283568">
@@ -1664,7 +1664,7 @@
<string name="kg_invalid_sim_puk_hint" msgid="2539364558870734339">"PUK-koden ska vara åtta siffror."</string>
<string name="kg_invalid_puk" msgid="4809502818518963344">"Ange rätt PUK-kod igen. Om försöken upprepas inaktiveras SIM-kortet permanent."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="4705368340409816254">"PIN-koderna stämmer inte överens"</string>
- <string name="kg_login_too_many_attempts" msgid="699292728290654121">"För många försök med grafiskt lösenord"</string>
+ <string name="kg_login_too_many_attempts" msgid="699292728290654121">"För många försök med mönster"</string>
<string name="kg_login_instructions" msgid="3619844310339066827">"Logga in med ditt Google-konto om du vill låsa upp."</string>
<string name="kg_login_username_hint" msgid="1765453775467133251">"Användarnamn (e-post)"</string>
<string name="kg_login_password_hint" msgid="3330530727273164402">"Lösenord"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index d68c088..893aeda 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -87,7 +87,7 @@
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ప్రాధాన్య నెట్వర్క్ను మార్చుకోవడానికి ప్రయత్నించండి. మార్చడానికి నొక్కండి."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"అత్యవసర కాలింగ్ అందుబాటులో లేదు"</string>
<string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Wi-Fiతో అత్యవసర కాల్లు చేయలేరు"</string>
- <string name="notification_channel_network_alert" msgid="4788053066033851841">"హెచ్చరికలు"</string>
+ <string name="notification_channel_network_alert" msgid="4788053066033851841">"అలర్ట్లు"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"కాల్ ఫార్వార్డింగ్"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"అత్యవసర కాల్బ్యాక్ మోడ్"</string>
<string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"మొబైల్ డేటా స్థితి"</string>
@@ -287,7 +287,7 @@
<string name="notification_channel_network_available" msgid="6083697929214165169">"నెట్వర్క్ అందుబాటులో ఉంది"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN స్థితి"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"మీ IT నిర్వాహకుల నుండి వచ్చే హెచ్చరికలు"</string>
- <string name="notification_channel_alerts" msgid="5070241039583668427">"హెచ్చరికలు"</string>
+ <string name="notification_channel_alerts" msgid="5070241039583668427">"అలర్ట్లు"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"రిటైల్ డెమో"</string>
<string name="notification_channel_usb" msgid="1528280969406244896">"USB కనెక్షన్"</string>
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"యాప్ అమలవుతోంది"</string>
@@ -815,7 +815,7 @@
<string name="phoneTypeTtyTdd" msgid="532038552105328779">"TTY TDD"</string>
<string name="phoneTypeWorkMobile" msgid="7522314392003565121">"కార్యాలయ మొబైల్"</string>
<string name="phoneTypeWorkPager" msgid="3748332310638505234">"కార్యాలయ పేజర్"</string>
- <string name="phoneTypeAssistant" msgid="757550783842231039">"Assistant"</string>
+ <string name="phoneTypeAssistant" msgid="757550783842231039">"అసిస్టెంట్"</string>
<string name="phoneTypeMms" msgid="1799747455131365989">"MMS"</string>
<string name="eventTypeCustom" msgid="3257367158986466481">"అనుకూలం"</string>
<string name="eventTypeBirthday" msgid="7770026752793912283">"పుట్టినరోజు"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 99d1516..1586f16 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -657,6 +657,9 @@
<!-- Indicate the display area rect for foldable devices in folded state. -->
<string name="config_foldedArea"></string>
+ <!-- Indicates whether to enable an animation when unfolding a device or not -->
+ <bool name="config_unfoldTransitionEnabled">false</bool>
+
<!-- Indicates that the device supports having more than one internal display on at the same
time. Only applicable to devices with more than one internal display. If this option is
set to false, DisplayManager will make additional effort to ensure no more than 1 internal
@@ -5044,4 +5047,80 @@
<!-- the number of the max cached processes in the system. -->
<integer name="config_customizedMaxCachedProcesses">32</integer>
+
+ <!-- The display cutout configs for secondary built-in display. -->
+ <string name="config_secondaryBuiltInDisplayCutout" translatable="false"></string>
+ <string name="config_secondaryBuiltInDisplayCutoutRectApproximation" translatable="false">
+ @string/config_secondaryBuiltInDisplayCutout
+ </string>
+ <bool name="config_fillSecondaryBuiltInDisplayCutout">false</bool>
+ <bool name="config_maskSecondaryBuiltInDisplayCutout">false</bool>
+
+ <!-- An array contains unique ids of all built-in displays and the unique id of a display can be
+ obtained from {@link Display#getUniqueId}. This array should be set for multi-display
+ devices if there are different display related configs(e.g. display cutout, rounded corner)
+ between each built-in display.
+ It is used as an index for multi-display related configs:
+ First look up the index of the unique id of the given built-in display unique id in this
+ array and use this index to get the info in corresponding config arrays such as:
+ - config_displayCutoutPathArray
+ - config_displayCutoutApproximationRectArray
+ - config_fillBuiltInDisplayCutoutArray
+ - config_maskBuiltInDisplayCutoutArray
+ - config_waterfallCutoutArray
+
+ Leave this array empty for single display device and the system will load the default main
+ built-in related configs.
+ -->
+ <string-array name="config_displayUniqueIdArray" translatable="false">
+ <!-- Example:
+ <item>"local:1234567891"</item> // main built-in display
+ <item>"local:1234567892"</item> // secondary built-in display
+ -->
+ </string-array>
+
+ <!-- The display cutout path config for each display in a multi-display device. -->
+ <string-array name="config_displayCutoutPathArray" translatable="false">
+ <item>@string/config_mainBuiltInDisplayCutout</item>
+ <item>@string/config_secondaryBuiltInDisplayCutout</item>
+ </string-array>
+
+ <!-- The display cutout approximation rect config for each display in a multi-display device.
+ -->
+ <string-array name="config_displayCutoutApproximationRectArray" translatable="false">
+ <item>@string/config_mainBuiltInDisplayCutoutRectApproximation</item>
+ <item>@string/config_secondaryBuiltInDisplayCutoutRectApproximation</item>
+ </string-array>
+
+ <!-- The maskBuiltInDisplayCutout config for each display in a multi-display device. -->
+ <array name="config_maskBuiltInDisplayCutoutArray" translatable="false">
+ <item>@bool/config_maskMainBuiltInDisplayCutout</item>
+ <item>@bool/config_maskSecondaryBuiltInDisplayCutout</item>
+ </array>
+
+ <!-- The fillBuiltInDisplayCutout config for each display in a multi-display device. -->
+ <array name="config_fillBuiltInDisplayCutoutArray" translatable="false">
+ <item>@bool/config_fillMainBuiltInDisplayCutout</item>
+ <item>@bool/config_fillSecondaryBuiltInDisplayCutout</item>
+ </array>
+
+ <array name="config_mainBuiltInDisplayWaterfallCutout" translatable="false">
+ <item>@dimen/waterfall_display_left_edge_size</item>
+ <item>@dimen/waterfall_display_top_edge_size</item>
+ <item>@dimen/waterfall_display_right_edge_size</item>
+ <item>@dimen/waterfall_display_bottom_edge_size</item>
+ </array>
+
+ <array name="config_secondaryBuiltInDisplayWaterfallCutout" translatable="false">
+ <item>@dimen/secondary_waterfall_display_left_edge_size</item>
+ <item>@dimen/secondary_waterfall_display_top_edge_size</item>
+ <item>@dimen/secondary_waterfall_display_right_edge_size</item>
+ <item>@dimen/secondary_waterfall_display_bottom_edge_size</item>
+ </array>
+
+ <!-- The waterfall cutout config for each display in a multi-display device. -->
+ <array name="config_waterfallCutoutArray" translatable="false">
+ <item>@array/config_mainBuiltInDisplayWaterfallCutout</item>
+ <item>@array/config_secondaryBuiltInDisplayWaterfallCutout</item>
+ </array>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index de7a117..7be9c7b 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -920,7 +920,7 @@
<dimen name="chooser_action_button_icon_size">18dp</dimen>
- <!-- For Waterfall Display -->
+ <!-- For main built-in Waterfall Display -->
<dimen name="waterfall_display_left_edge_size">0px</dimen>
<dimen name="waterfall_display_top_edge_size">0px</dimen>
<dimen name="waterfall_display_right_edge_size">0px</dimen>
@@ -943,4 +943,10 @@
<dimen name="starting_surface_icon_size">160dp</dimen>
<!-- The default width/height of the icon on the spec of adaptive icon drawable. -->
<dimen name="starting_surface_default_icon_size">108dp</dimen>
+
+ <!-- For secondary built-in Waterfall Display -->
+ <dimen name="secondary_waterfall_display_left_edge_size">0px</dimen>
+ <dimen name="secondary_waterfall_display_top_edge_size">0px</dimen>
+ <dimen name="secondary_waterfall_display_right_edge_size">0px</dimen>
+ <dimen name="secondary_waterfall_display_bottom_edge_size">0px</dimen>
</resources>
diff --git a/core/res/res/values/dimens_car.xml b/core/res/res/values/dimens_car.xml
index 0ef60c4..36f1edb 100644
--- a/core/res/res/values/dimens_car.xml
+++ b/core/res/res/values/dimens_car.xml
@@ -110,10 +110,10 @@
<dimen name="car_textview_fading_edge_length">40dp</dimen>
<!-- Dialog start padding for button bar layout -->
- <dimen name="button_bar_layout_start_padding">@*android:dimen/car_keyline_1</dimen>
+ <dimen name="button_bar_layout_start_padding">@dimen/car_padding_2</dimen>
<!-- Dialog end padding for button bar layout -->
- <dimen name="button_bar_layout_end_padding">@*android:dimen/car_keyline_1</dimen>
+ <dimen name="button_bar_layout_end_padding">@dimen/car_padding_2</dimen>
<!-- Dialog top padding for button bar layout -->
<dimen name="button_bar_layout_top_padding">@*android:dimen/car_padding_2</dimen>
@@ -122,7 +122,7 @@
<dimen name="button_layout_height">@*android:dimen/car_card_action_bar_height</dimen>
<!-- Dialog button end margin -->
- <dimen name="button_end_margin">@*android:dimen/car_padding_4</dimen>
+ <dimen name="button_end_margin">@*android:dimen/car_padding_2</dimen>
<!-- Dialog top padding when there is no title -->
<dimen name="dialog_no_title_padding_top">@*android:dimen/car_padding_4</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index adb046e..cd590cbb 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3837,6 +3837,7 @@
<java-symbol type="array" name="config_foldedDeviceStates" />
<java-symbol type="string" name="config_foldedArea" />
<java-symbol type="bool" name="config_supportsConcurrentInternalDisplays" />
+ <java-symbol type="bool" name="config_unfoldTransitionEnabled" />
<java-symbol type="array" name="config_disableApksUnlessMatchedSku_apk_list" />
<java-symbol type="array" name="config_disableApkUnlessMatchedSku_skus_list" />
@@ -4425,4 +4426,21 @@
<java-symbol type="bool" name="config_volumeShowRemoteSessions" />
<java-symbol type="integer" name="config_customizedMaxCachedProcesses" />
+
+ <java-symbol type="string" name="config_secondaryBuiltInDisplayCutout" />
+ <java-symbol type="string" name="config_secondaryBuiltInDisplayCutoutRectApproximation" />
+ <java-symbol type="bool" name="config_fillSecondaryBuiltInDisplayCutout" />
+ <java-symbol type="bool" name="config_maskSecondaryBuiltInDisplayCutout" />
+ <java-symbol type="array" name="config_displayUniqueIdArray" />
+ <java-symbol type="array" name="config_displayCutoutPathArray" />
+ <java-symbol type="array" name="config_displayCutoutApproximationRectArray" />
+ <java-symbol type="array" name="config_fillBuiltInDisplayCutoutArray" />
+ <java-symbol type="array" name="config_maskBuiltInDisplayCutoutArray" />
+ <java-symbol type="dimen" name="secondary_waterfall_display_left_edge_size" />
+ <java-symbol type="dimen" name="secondary_waterfall_display_top_edge_size" />
+ <java-symbol type="dimen" name="secondary_waterfall_display_right_edge_size" />
+ <java-symbol type="dimen" name="secondary_waterfall_display_bottom_edge_size" />
+ <java-symbol type="array" name="config_mainBuiltInDisplayWaterfallCutout" />
+ <java-symbol type="array" name="config_secondaryBuiltInDisplayWaterfallCutout" />
+ <java-symbol type="array" name="config_waterfallCutoutArray" />
</resources>
diff --git a/core/tests/coretests/src/android/app/appsearch/AppSearchSessionUnitTest.java b/core/tests/coretests/src/android/app/appsearch/AppSearchSessionUnitTest.java
index d51004c..07e4333 100644
--- a/core/tests/coretests/src/android/app/appsearch/AppSearchSessionUnitTest.java
+++ b/core/tests/coretests/src/android/app/appsearch/AppSearchSessionUnitTest.java
@@ -16,6 +16,8 @@
package android.app.appsearch;
+import static android.app.appsearch.SearchSpec.TERM_MATCH_PREFIX;
+
import static com.google.common.truth.Truth.assertThat;
import static org.testng.Assert.expectThrows;
@@ -30,6 +32,8 @@
import org.junit.Before;
import org.junit.Test;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@@ -100,4 +104,127 @@
.isEqualTo(AppSearchResult.RESULT_INTERNAL_ERROR);
assertThat(appSearchException.getMessage()).startsWith("NullPointerException");
}
+
+ @Test
+ public void testGetEmptyNextPage() throws Exception {
+ // Set the schema.
+ CompletableFuture<AppSearchResult<SetSchemaResponse>> schemaFuture =
+ new CompletableFuture<>();
+ mSearchSession.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(new AppSearchSchema.Builder("schema1").build())
+ .setForceOverride(true).build(),
+ mExecutor, mExecutor, schemaFuture::complete);
+ schemaFuture.get().getResultValue();
+
+ // Create a document and index it.
+ GenericDocument document1 = new GenericDocument.Builder<>("namespace", "id1",
+ "schema1").build();
+ CompletableFuture<AppSearchBatchResult<String, Void>> putDocumentsFuture =
+ new CompletableFuture<>();
+ mSearchSession.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(document1).build(),
+ mExecutor, new BatchResultCallback<String, Void>() {
+ @Override
+ public void onResult(AppSearchBatchResult<String, Void> result) {
+ putDocumentsFuture.complete(result);
+ }
+
+ @Override
+ public void onSystemError(Throwable throwable) {
+ putDocumentsFuture.completeExceptionally(throwable);
+ }
+ });
+ putDocumentsFuture.get();
+
+ // Search and get the first page.
+ SearchSpec searchSpec = new SearchSpec.Builder()
+ .setTermMatch(TERM_MATCH_PREFIX)
+ .setResultCountPerPage(1)
+ .build();
+ SearchResults searchResults = mSearchSession.search("", searchSpec);
+
+ CompletableFuture<AppSearchResult<List<SearchResult>>> getNextPageFuture =
+ new CompletableFuture<>();
+ searchResults.getNextPage(mExecutor, getNextPageFuture::complete);
+ List<SearchResult> results = getNextPageFuture.get().getResultValue();
+ assertThat(results).hasSize(1);
+ assertThat(results.get(0).getGenericDocument()).isEqualTo(document1);
+
+ // We get all documents, and it shouldn't fail if we keep calling getNextPage().
+ getNextPageFuture = new CompletableFuture<>();
+ searchResults.getNextPage(mExecutor, getNextPageFuture::complete);
+ results = getNextPageFuture.get().getResultValue();
+ assertThat(results).isEmpty();
+ }
+
+ @Test
+ public void testGetEmptyNextPage_multiPages() throws Exception {
+ // Set the schema.
+ CompletableFuture<AppSearchResult<SetSchemaResponse>> schemaFuture =
+ new CompletableFuture<>();
+ mSearchSession.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(new AppSearchSchema.Builder("schema1").build())
+ .setForceOverride(true).build(),
+ mExecutor, mExecutor, schemaFuture::complete);
+ schemaFuture.get().getResultValue();
+
+ // Create a document and insert 3 package1 documents
+ GenericDocument document1 = new GenericDocument.Builder<>("namespace", "id1",
+ "schema1").build();
+ GenericDocument document2 = new GenericDocument.Builder<>("namespace", "id2",
+ "schema1").build();
+ GenericDocument document3 = new GenericDocument.Builder<>("namespace", "id3",
+ "schema1").build();
+ CompletableFuture<AppSearchBatchResult<String, Void>> putDocumentsFuture =
+ new CompletableFuture<>();
+ mSearchSession.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(document1, document2, document3).build(),
+ mExecutor, new BatchResultCallback<String, Void>() {
+ @Override
+ public void onResult(AppSearchBatchResult<String, Void> result) {
+ putDocumentsFuture.complete(result);
+ }
+
+ @Override
+ public void onSystemError(Throwable throwable) {
+ putDocumentsFuture.completeExceptionally(throwable);
+ }
+ });
+ putDocumentsFuture.get();
+
+ // Search for only 2 result per page
+ SearchSpec searchSpec = new SearchSpec.Builder()
+ .setTermMatch(TERM_MATCH_PREFIX)
+ .setResultCountPerPage(2)
+ .build();
+ SearchResults searchResults = mSearchSession.search("", searchSpec);
+
+ // Get the first page, it contains 2 results.
+ List<GenericDocument> outDocs = new ArrayList<>();
+ CompletableFuture<AppSearchResult<List<SearchResult>>> getNextPageFuture =
+ new CompletableFuture<>();
+ searchResults.getNextPage(mExecutor, getNextPageFuture::complete);
+ List<SearchResult> results = getNextPageFuture.get().getResultValue();
+ assertThat(results).hasSize(2);
+ outDocs.add(results.get(0).getGenericDocument());
+ outDocs.add(results.get(1).getGenericDocument());
+
+ // Get the second page, it contains only 1 result.
+ getNextPageFuture = new CompletableFuture<>();
+ searchResults.getNextPage(mExecutor, getNextPageFuture::complete);
+ results = getNextPageFuture.get().getResultValue();
+ assertThat(results).hasSize(1);
+ outDocs.add(results.get(0).getGenericDocument());
+
+ assertThat(outDocs).containsExactly(document1, document2, document3);
+
+ // We get all documents, and it shouldn't fail if we keep calling getNextPage().
+ getNextPageFuture = new CompletableFuture<>();
+ searchResults.getNextPage(mExecutor, getNextPageFuture::complete);
+ results = getNextPageFuture.get().getResultValue();
+ assertThat(results).isEmpty();
+ }
}
diff --git a/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java b/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
index 7dea82d..69eb13f 100644
--- a/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
+++ b/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
@@ -22,12 +22,6 @@
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeNotNull;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
import android.os.PerformanceHintManager.Session;
@@ -120,92 +114,9 @@
}
@Test
- public void testRateLimitWithDurationFastEnough() throws Exception {
- FakeClock fakeClock = new FakeClock();
- Session s = new Session(mIHintSessionMock, fakeClock, RATE_1000, TARGET_166);
-
- reset(mIHintSessionMock);
- fakeClock.setNow(0);
- s.updateTargetWorkDuration(TARGET_166);
-
- s.reportActualWorkDuration(TARGET_166 - 1);
- s.reportActualWorkDuration(TARGET_166);
- // we should not see update as the rate should be 10X for over-perform case.
- verify(mIHintSessionMock, never()).reportActualWorkDuration(any(), any());
- fakeClock.incrementClock(10 * RATE_1000);
- s.reportActualWorkDuration(TARGET_166);
- verify(mIHintSessionMock, never()).reportActualWorkDuration(any(), any());
- fakeClock.incrementClock(1);
- s.reportActualWorkDuration(TARGET_166);
- // we should see update after rate limit
- verify(mIHintSessionMock, times(1)).reportActualWorkDuration(
- eq(new long[] {TARGET_166 - 1, TARGET_166, TARGET_166, TARGET_166}),
- eq(new long[] {0, 0, 10 * RATE_1000, 10 * RATE_1000 + 1}));
-
- reset(mIHintSessionMock);
- s.reportActualWorkDuration(TARGET_166);
- s.reportActualWorkDuration(TARGET_166 - 1);
- s.reportActualWorkDuration(TARGET_166 - 2);
- // we should not see update as the rate should be 10X for over-perform case.
- verify(mIHintSessionMock, never()).reportActualWorkDuration(any(), any());
- fakeClock.incrementClock(10 * RATE_1000 + 1);
- s.reportActualWorkDuration(TARGET_166);
- s.reportActualWorkDuration(TARGET_166 - 1);
- // we should see update now
- verify(mIHintSessionMock, times(1)).reportActualWorkDuration(
- eq(new long[] {TARGET_166, TARGET_166 - 1, TARGET_166 - 2, TARGET_166}),
- eq(new long[] {10 * RATE_1000 + 1, 10 * RATE_1000 + 1, 10 * RATE_1000 + 1,
- (10 * RATE_1000 + 1) * 2}));
- }
-
- @Test
- public void testRateLimitWithDurationTooSlow() throws Exception {
- FakeClock fakeClock = new FakeClock();
- Session s = new Session(mIHintSessionMock, fakeClock, RATE_1000, TARGET_166);
-
- reset(mIHintSessionMock);
- fakeClock.setNow(0);
- s.updateTargetWorkDuration(TARGET_166);
-
- verify(mIHintSessionMock, times(1)).updateTargetWorkDuration(eq(TARGET_166));
- // shouldn't update before rate limit
- s.reportActualWorkDuration(TARGET_166 + 1);
- verify(mIHintSessionMock, never()).reportActualWorkDuration(any(), any());
-
- // shouldn't update when the time is exactly at rate limit
- fakeClock.incrementClock(RATE_1000);
- s.reportActualWorkDuration(TARGET_166 + 1);
- verify(mIHintSessionMock, never()).reportActualWorkDuration(any(), any());
-
- // should be ready for sending hint
- fakeClock.incrementClock(1);
- s.reportActualWorkDuration(TARGET_166 + 1);
- verify(mIHintSessionMock, times(1)).reportActualWorkDuration(
- eq(new long[] {TARGET_166 + 1, TARGET_166 + 1, TARGET_166 + 1}),
- eq(new long[] {0 , RATE_1000, RATE_1000 + 1}));
- }
-
- @Test
public void testCloseHintSession() {
Session s = createSession();
assumeNotNull(s);
s.close();
}
-
- private static class FakeClock implements PerformanceHintManager.NanoClock {
- private long mCurrentTime = 0L;
-
- @Override
- public long nanos() {
- return mCurrentTime;
- }
-
- public void setNow(long nanos) {
- mCurrentTime = nanos;
- }
-
- public void incrementClock(long nanos) {
- mCurrentTime += nanos;
- }
- }
}
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 6301f32..507638e 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -698,15 +698,15 @@
@Test
public void testRequestedState() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
- final InsetsState state = mTestHost.getRequestedState();
+ final InsetsVisibilities request = mTestHost.getRequestedVisibilities();
mController.hide(statusBars() | navigationBars());
- assertFalse(state.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR));
- assertFalse(state.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR));
+ assertFalse(request.getVisibility(ITYPE_STATUS_BAR));
+ assertFalse(request.getVisibility(ITYPE_NAVIGATION_BAR));
mController.show(statusBars() | navigationBars());
- assertTrue(state.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR));
- assertTrue(state.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR));
+ assertTrue(request.getVisibility(ITYPE_STATUS_BAR));
+ assertTrue(request.getVisibility(ITYPE_NAVIGATION_BAR));
});
}
@@ -837,20 +837,20 @@
public static class TestHost extends ViewRootInsetsControllerHost {
- private final InsetsState mRequestedState = new InsetsState();
+ private final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
TestHost(ViewRootImpl viewRoot) {
super(viewRoot);
}
@Override
- public void onInsetsModified(InsetsState insetsState) {
- mRequestedState.set(insetsState, true);
- super.onInsetsModified(insetsState);
+ public void updateRequestedVisibilities(InsetsVisibilities visibilities) {
+ mRequestedVisibilities.set(visibilities);
+ super.updateRequestedVisibilities(visibilities);
}
- public InsetsState getRequestedState() {
- return mRequestedState;
+ public InsetsVisibilities getRequestedVisibilities() {
+ return mRequestedVisibilities;
}
}
}
diff --git a/core/tests/coretests/src/android/view/InsetsVisibilitiesTest.java b/core/tests/coretests/src/android/view/InsetsVisibilitiesTest.java
new file mode 100644
index 0000000..5664e0b
--- /dev/null
+++ b/core/tests/coretests/src/android/view/InsetsVisibilitiesTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static android.view.InsetsState.FIRST_TYPE;
+import static android.view.InsetsState.LAST_TYPE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.Presubmit;
+import android.view.InsetsState.InternalInsetsType;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link InsetsVisibilities}.
+ *
+ * <p>Build/Install/Run:
+ * atest FrameworksCoreTests:InsetsVisibilities
+ *
+ * <p>This test class is a part of Window Manager Service tests and specified in
+ * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}.
+ */
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class InsetsVisibilitiesTest {
+
+ @Test
+ public void testEquals() {
+ final InsetsVisibilities v1 = new InsetsVisibilities();
+ final InsetsVisibilities v2 = new InsetsVisibilities();
+ final InsetsVisibilities v3 = new InsetsVisibilities();
+ assertEquals(v1, v2);
+ assertEquals(v1, v3);
+
+ for (@InternalInsetsType int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
+ v1.setVisibility(type, false);
+ v2.setVisibility(type, false);
+ }
+ assertEquals(v1, v2);
+ assertNotEquals(v1, v3);
+
+ for (@InternalInsetsType int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
+ v1.setVisibility(type, true);
+ v2.setVisibility(type, true);
+ }
+ assertEquals(v1, v2);
+ assertNotEquals(v1, v3);
+ }
+
+ @Test
+ public void testSet() {
+ for (@InternalInsetsType int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
+ final InsetsVisibilities v1 = new InsetsVisibilities();
+ final InsetsVisibilities v2 = new InsetsVisibilities();
+
+ v1.setVisibility(type, true);
+ assertNotEquals(v1, v2);
+
+ v2.set(v1);
+ assertEquals(v1, v2);
+
+ v2.setVisibility(type, false);
+ assertNotEquals(v1, v2);
+
+ v1.set(v2);
+ assertEquals(v1, v2);
+ }
+ }
+
+ @Test
+ public void testCopyConstructor() {
+ for (@InternalInsetsType int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
+ final InsetsVisibilities v1 = new InsetsVisibilities();
+ v1.setVisibility(type, true);
+ final InsetsVisibilities v2 = new InsetsVisibilities(v1);
+ assertEquals(v1, v2);
+
+ v2.setVisibility(type, false);
+ assertNotEquals(v1, v2);
+ }
+ }
+
+ @Test
+ public void testGetterAndSetter() {
+ final InsetsVisibilities v1 = new InsetsVisibilities();
+ final InsetsVisibilities v2 = new InsetsVisibilities();
+
+ for (@InternalInsetsType int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
+ assertEquals(InsetsState.getDefaultVisibility(type), v1.getVisibility(type));
+ }
+
+ for (@InternalInsetsType int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
+ v1.setVisibility(type, true);
+ assertTrue(v1.getVisibility(type));
+
+ v2.setVisibility(type, false);
+ assertFalse(v2.getVisibility(type));
+ }
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
index 7d4412c..0f05be0 100644
--- a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
+++ b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
@@ -24,7 +24,7 @@
import android.os.Parcel;
import android.os.UserHandle;
import android.util.ArrayMap;
-import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -60,7 +60,7 @@
new Binder() /* imeToken */,
true /* navbarColorManagedByIme */,
BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE,
- new InsetsState() /* requestedState */,
+ new InsetsVisibilities() /* requestedVisibilities */,
"test" /* packageName */,
new int[0] /* transientBarTypes */);
@@ -81,7 +81,7 @@
assertThat(copy.mImeToken).isSameInstanceAs(original.mImeToken);
assertThat(copy.mNavbarColorManagedByIme).isEqualTo(original.mNavbarColorManagedByIme);
assertThat(copy.mBehavior).isEqualTo(original.mBehavior);
- assertThat(copy.mRequestedState).isEqualTo(original.mRequestedState);
+ assertThat(copy.mRequestedVisibilities).isEqualTo(original.mRequestedVisibilities);
assertThat(copy.mPackageName).isEqualTo(original.mPackageName);
assertThat(copy.mTransientBarTypes).isEqualTo(original.mTransientBarTypes);
}
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index fe04f0d..c3b1cd74 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -28,7 +28,6 @@
import android.hardware.display.DisplayManager;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
-import android.os.PerformanceHintManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
@@ -856,36 +855,6 @@
callback.onPictureCaptured(picture);
}
- /** called by native */
- static PerformanceHintManager.Session createHintSession(int[] tids) {
- PerformanceHintManager performanceHintManager =
- ProcessInitializer.sInstance.getHintManager();
- if (performanceHintManager == null) {
- return null;
- }
- // Native code will always set a target duration before reporting actual durations.
- // So this is just a placeholder value that's never used.
- long targetDurationNanos = 16666667;
- return performanceHintManager.createHintSession(tids, targetDurationNanos);
- }
-
- /** called by native */
- static void updateTargetWorkDuration(PerformanceHintManager.Session session,
- long targetDurationNanos) {
- session.updateTargetWorkDuration(targetDurationNanos);
- }
-
- /** called by native */
- static void reportActualWorkDuration(PerformanceHintManager.Session session,
- long actualDurationNanos) {
- session.reportActualWorkDuration(actualDurationNanos);
- }
-
- /** called by native */
- static void closeHintSession(PerformanceHintManager.Session session) {
- session.close();
- }
-
/**
* Interface used to receive callbacks when Webview requests a surface control.
*
@@ -1152,7 +1121,6 @@
private boolean mIsolated = false;
private Context mContext;
private String mPackageName;
- private PerformanceHintManager mPerformanceHintManager;
private IGraphicsStats mGraphicsStatsService;
private IGraphicsStatsCallback mGraphicsStatsCallback = new IGraphicsStatsCallback.Stub() {
@Override
@@ -1164,10 +1132,6 @@
private ProcessInitializer() {
}
- synchronized PerformanceHintManager getHintManager() {
- return mPerformanceHintManager;
- }
-
synchronized void setPackageName(String name) {
if (mInitialized) return;
mPackageName = name;
@@ -1218,10 +1182,6 @@
initDisplayInfo();
- // HintManager and HintSession are designed to be accessible from isoalted processes
- // so not checking for isolated process here.
- initHintSession();
-
nSetIsHighEndGfx(ActivityManager.isHighEndGfx());
// Defensively clear out the context in case we were passed a context that can leak
// if we live longer than it, e.g. an activity context.
@@ -1265,11 +1225,6 @@
mDisplayInitialized = true;
}
- private void initHintSession() {
- if (mContext == null) return;
- mPerformanceHintManager = mContext.getSystemService(PerformanceHintManager.class);
- }
-
private void rotateBuffer() {
nRotateProcessStatsBuffer();
requestBuffer();
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
index 48d78cf..27bd53d 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
@@ -175,7 +175,8 @@
final TaskFragmentCreationParams fragmentOptions =
createFragmentOptions(fragmentToken, ownerToken, bounds, windowingMode);
wct.createTaskFragment(fragmentOptions)
- .startActivityInTaskFragment(fragmentToken, activityIntent, activityOptions);
+ .startActivityInTaskFragment(fragmentToken, ownerToken, activityIntent,
+ activityOptions);
}
TaskFragmentCreationParams createFragmentOptions(IBinder fragmentToken, IBinder ownerToken,
@@ -186,7 +187,7 @@
}
return new TaskFragmentCreationParams.Builder(
- getIOrganizer(),
+ getOrganizerToken(),
fragmentToken,
ownerToken)
.setInitialBounds(bounds)
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
index 7298d34..407c43d 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
@@ -26,7 +26,9 @@
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.window.TaskFragmentAppearedInfo;
import android.window.TaskFragmentInfo;
import android.window.WindowContainerTransaction;
@@ -40,6 +42,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.Executor;
/**
* Main controller class that manages split states and presentation.
@@ -57,8 +60,7 @@
private SplitOrganizerCallback mSplitOrganizerCallback;
public SplitController() {
- mPresenter = new SplitPresenter(ActivityThread.currentActivityThread().getExecutor(),
- this);
+ mPresenter = new SplitPresenter(new MainThreadExecutor(), this);
// Register a callback to be notified about activities being created.
ActivityThread.currentActivityThread().getApplication().registerActivityLifecycleCallbacks(
new LifecycleCallbacks());
@@ -99,39 +101,38 @@
@Override
public void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo) {
- for (TaskFragmentContainer container : mContainers) {
- if (container.getTaskFragmentToken().equals(
- taskFragmentAppearedInfo.getTaskFragmentInfo().getFragmentToken())) {
- container.setInfo(taskFragmentAppearedInfo.getTaskFragmentInfo());
- return;
- }
+ TaskFragmentContainer container = getContainer(
+ taskFragmentAppearedInfo.getTaskFragmentInfo().getFragmentToken());
+ if (container == null) {
+ return;
}
+
+ container.setInfo(taskFragmentAppearedInfo.getTaskFragmentInfo());
}
@Override
public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) {
- for (TaskFragmentContainer container : mContainers) {
- if (container.getTaskFragmentToken().equals(taskFragmentInfo.getFragmentToken())) {
- container.setInfo(taskFragmentInfo);
+ TaskFragmentContainer container = getContainer(taskFragmentInfo.getFragmentToken());
+ if (container == null) {
+ return;
+ }
- if (taskFragmentInfo.isEmpty()) {
- cleanupContainer(container, true /* shouldFinishDependent */);
- updateCallbackIfNecessary();
- }
- return;
- }
+ container.setInfo(taskFragmentInfo);
+ if (taskFragmentInfo.isEmpty()) {
+ cleanupContainer(container, true /* shouldFinishDependent */);
+ updateCallbackIfNecessary();
}
}
@Override
public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) {
- for (TaskFragmentContainer container : mContainers) {
- if (container.getTaskFragmentToken().equals(taskFragmentInfo.getFragmentToken())) {
- cleanupContainer(container, true /* shouldFinishDependent */);
- updateCallbackIfNecessary();
- return;
- }
+ TaskFragmentContainer container = getContainer(taskFragmentInfo.getFragmentToken());
+ if (container == null) {
+ return;
}
+
+ cleanupContainer(container, true /* shouldFinishDependent */);
+ updateCallbackIfNecessary();
}
@Override
@@ -148,6 +149,7 @@
* Checks if the activity start should be routed to a particular container. It can create a new
* container for the activity and a new split container if necessary.
*/
+ // TODO(b/190433398): Break down into smaller functions.
void onActivityCreated(@NonNull Activity launchedActivity) {
final ComponentName componentName = launchedActivity.getComponentName();
@@ -201,6 +203,18 @@
return;
}
+ // Check if the split is already set.
+ final TaskFragmentContainer activityBelowContainer = getContainerWithActivity(
+ activityBelow.getActivityToken());
+ if (currentContainer != null && activityBelowContainer != null) {
+ final SplitContainer existingSplit = getActiveSplitForContainers(currentContainer,
+ activityBelowContainer);
+ if (existingSplit != null) {
+ // There is already an active split with the activity below.
+ return;
+ }
+ }
+
final ExtensionSplitPairRule splitPairRule = getSplitRule(
activityBelow.getComponentName(), componentName, splitRules);
if (splitPairRule == null) {
@@ -213,6 +227,20 @@
updateCallbackIfNecessary();
}
+ private void onActivityConfigurationChanged(@NonNull Activity activity) {
+ final TaskFragmentContainer currentContainer = getContainerWithActivity(
+ activity.getActivityToken());
+
+ if (currentContainer != null) {
+ // Changes to activities in controllers are handled in
+ // onTaskFragmentParentInfoChanged
+ return;
+ }
+
+ // Check if activity requires a placeholder
+ launchPlaceholderIfNecessary(activity);
+ }
+
/**
* Returns a container that this activity is registered with. An activity can only belong to one
* container, or no container at all.
@@ -324,7 +352,7 @@
}
/**
- * Returns the top active split container that has the provided container.
+ * Returns the top active split container that has the provided container, if available.
*/
@Nullable
private SplitContainer getActiveSplitForContainer(@NonNull TaskFragmentContainer container) {
@@ -339,6 +367,26 @@
}
/**
+ * Returns the active split that has the provided containers as primary and secondary or as
+ * secondary and primary, if available.
+ */
+ @Nullable
+ private SplitContainer getActiveSplitForContainers(
+ @NonNull TaskFragmentContainer firstContainer,
+ @NonNull TaskFragmentContainer secondContainer) {
+ for (int i = mSplitContainers.size() - 1; i >= 0; i--) {
+ SplitContainer splitContainer = mSplitContainers.get(i);
+ final TaskFragmentContainer primary = splitContainer.getPrimaryContainer();
+ final TaskFragmentContainer secondary = splitContainer.getSecondaryContainer();
+ if ((firstContainer == secondary && secondContainer == primary)
+ || (firstContainer == primary && secondContainer == secondary)) {
+ return splitContainer;
+ }
+ }
+ return null;
+ }
+
+ /**
* Checks if the container requires a placeholder and launches it if necessary.
*/
private boolean launchPlaceholderIfNecessary(@NonNull TaskFragmentContainer container) {
@@ -480,7 +528,7 @@
}
@Nullable
- private TaskFragmentContainer getContainer(@NonNull IBinder fragmentToken) {
+ TaskFragmentContainer getContainer(@NonNull IBinder fragmentToken) {
for (TaskFragmentContainer container : mContainers) {
if (container.getTaskFragmentToken().equals(fragmentToken)) {
return container;
@@ -546,6 +594,10 @@
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+ }
+
+ @Override
+ public void onActivityPostCreated(Activity activity, Bundle savedInstanceState) {
// Calling after Activity#onCreate is complete to allow the app launch something
// first. In case of a configured placeholder activity we want to make sure
// that we don't launch it if an activity itself already requested something to be
@@ -576,5 +628,20 @@
@Override
public void onActivityDestroyed(Activity activity) {
}
+
+ @Override
+ public void onActivityConfigurationChanged(Activity activity) {
+ SplitController.this.onActivityConfigurationChanged(activity);
+ }
+ }
+
+ /** Executor that posts on the main application thread. */
+ private static class MainThreadExecutor implements Executor {
+ private final Handler handler = new Handler(Looper.getMainLooper());
+
+ @Override
+ public void execute(Runnable r) {
+ handler.post(r);
+ }
}
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java
index 381d6d7..90af72b 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java
@@ -23,6 +23,7 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
+import android.os.IBinder;
import android.window.TaskFragmentCreationParams;
import android.window.WindowContainerTransaction;
@@ -98,8 +99,6 @@
final Rect parentBounds = getParentContainerBounds(primaryActivity);
final Rect primaryRectBounds = getBoundsForPosition(POSITION_LEFT, parentBounds, rule);
- final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
-
TaskFragmentContainer primaryContainer = mController.getContainerWithActivity(
primaryActivity.getActivityToken());
if (primaryContainer == null) {
@@ -115,10 +114,13 @@
wct.reparentActivityToTaskFragment(primaryContainer.getTaskFragmentToken(),
primaryActivity.getActivityToken());
+
+ primaryContainer.setLastRequestedBounds(primaryRectBounds);
} else {
resizeTaskFragmentIfRegistered(wct, primaryContainer, primaryRectBounds);
}
+ final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
TaskFragmentContainer secondaryContainer = mController.getContainerWithActivity(
secondaryActivity.getActivityToken());
if (secondaryContainer == null || secondaryContainer == primaryContainer) {
@@ -134,6 +136,8 @@
wct.reparentActivityToTaskFragment(secondaryContainer.getTaskFragmentToken(),
secondaryActivity.getActivityToken());
+
+ secondaryContainer.setLastRequestedBounds(secondaryRectBounds);
} else {
resizeTaskFragmentIfRegistered(wct, secondaryContainer, secondaryRectBounds);
}
@@ -177,6 +181,9 @@
activityIntent,
activityOptions);
+ primaryContainer.setLastRequestedBounds(primaryRectBounds);
+ secondaryContainer.setLastRequestedBounds(secondaryRectBounds);
+
// TODO(b/190433398): The primary container and the secondary container should also be set
// as adjacent (WCT#setAdjacentRoots) to make activities behind invisible.
@@ -199,7 +206,6 @@
final Rect primaryRectBounds = getBoundsForPosition(POSITION_LEFT, parentBounds, rule);
final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
- // TODO(b/190433398): Check if the bounds actually changed.
// If the task fragments are not registered yet, the positions will be updated after they
// are created again.
resizeTaskFragmentIfRegistered(wct, splitContainer.getPrimaryContainer(),
@@ -219,10 +225,27 @@
if (container.getInfo() == null) {
return;
}
- // TODO(b/190433398): Check if the bounds actually changed.
resizeTaskFragment(wct, container.getTaskFragmentToken(), bounds);
}
+ @Override
+ void resizeTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken,
+ @Nullable Rect bounds) {
+ TaskFragmentContainer container = mController.getContainer(fragmentToken);
+ if (container == null) {
+ throw new IllegalStateException(
+ "Resizing a task fragment that is not registered with controller.");
+ }
+
+ if (container.areLastRequestedBoundsEqual(bounds)) {
+ // Return early if the provided bounds were already requested
+ return;
+ }
+
+ container.setLastRequestedBounds(bounds);
+ super.resizeTaskFragment(wct, fragmentToken, bounds);
+ }
+
boolean shouldShowSideBySide(@NonNull SplitContainer splitContainer) {
final Rect parentBounds = getParentContainerBounds(splitContainer.getPrimaryContainer());
return shouldShowSideBySide(parentBounds, splitContainer.getSplitPairRule());
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java
index 3cf37a6..368adef 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityThread;
+import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.window.TaskFragmentInfo;
@@ -60,6 +61,11 @@
private boolean mIsFinished;
/**
+ * Bounds that were requested last via {@link android.window.WindowContainerTransaction}.
+ */
+ private final Rect mLastRequestedBounds = new Rect();
+
+ /**
* Creates a container with an existing activity that will be re-parented to it in a window
* container transaction.
*/
@@ -199,4 +205,23 @@
boolean isFinished() {
return mIsFinished;
}
+
+ /**
+ * Checks if last requested bounds are equal to the provided value.
+ */
+ boolean areLastRequestedBoundsEqual(@Nullable Rect bounds) {
+ return (bounds == null && mLastRequestedBounds.isEmpty())
+ || mLastRequestedBounds.equals(bounds);
+ }
+
+ /**
+ * Updates the last requested bounds.
+ */
+ void setLastRequestedBounds(@Nullable Rect bounds) {
+ if (bounds == null) {
+ mLastRequestedBounds.setEmpty();
+ } else {
+ mLastRequestedBounds.set(bounds);
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/res/color/one_handed_tutorial_background_color.xml b/libs/WindowManager/Shell/res/color/one_handed_tutorial_background_color.xml
new file mode 100644
index 0000000..4f56e0f
--- /dev/null
+++ b/libs/WindowManager/Shell/res/color/one_handed_tutorial_background_color.xml
@@ -0,0 +1,21 @@
+<?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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item android:color="?androidprv:attr/colorSurfaceVariant"/>
+</selector>
diff --git a/libs/WindowManager/Shell/res/drawable-hdpi/one_handed_tutorial.png b/libs/WindowManager/Shell/res/drawable-hdpi/one_handed_tutorial.png
deleted file mode 100644
index 6c1f1cf..0000000
--- a/libs/WindowManager/Shell/res/drawable-hdpi/one_handed_tutorial.png
+++ /dev/null
Binary files differ
diff --git a/libs/WindowManager/Shell/res/drawable/one_handed_tutorial_icon.xml b/libs/WindowManager/Shell/res/drawable/one_handed_tutorial_icon.xml
new file mode 100644
index 0000000..b32f34e
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/one_handed_tutorial_icon.xml
@@ -0,0 +1,14 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="60dp"
+ android:viewportWidth="32"
+ android:viewportHeight="60">
+ <path
+ android:pathData="M1.9703,30.5041C1.9703,28.295 3.7612,26.5042 5.9703,26.5042H25.5551C27.7642,26.5042 29.5551,28.295 29.5551,30.5042V54.0296C29.5551,56.2387 27.7642,58.0296 25.5551,58.0296H5.9703C3.7612,58.0296 1.9703,56.2387 1.9703,54.0296V30.5041Z"
+ android:fillColor="#000000"
+ android:fillAlpha="0.16"/>
+ <path
+ android:pathData="M25.5254,2H6C3.7909,2 2,3.7909 2,6V54C2,56.2091 3.7909,58 6,58H25.5254C27.7346,58 29.5254,56.2091 29.5254,54V6C29.5254,3.7909 27.7346,2 25.5254,2ZM6,0C2.6863,0 0,2.6863 0,6V54C0,57.3137 2.6863,60 6,60H25.5254C28.8391,60 31.5254,57.3137 31.5254,54V6C31.5254,2.6863 28.8391,0 25.5254,0H6ZM12.2034,47.2336L12.8307,47.861L15.3178,45.3783V52.1277H16.2076V45.3783L18.6903,47.8654L19.322,47.2336L15.7627,43.6743L12.2034,47.2336ZM19.7034,55.0742H11.822V56.552H19.7034V55.0742Z"
+ android:fillColor="#000000"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/libs/WindowManager/Shell/res/layout/one_handed_tutorial.xml b/libs/WindowManager/Shell/res/layout/one_handed_tutorial.xml
index 0190aad..d29ed8b 100644
--- a/libs/WindowManager/Shell/res/layout/one_handed_tutorial.xml
+++ b/libs/WindowManager/Shell/res/layout/one_handed_tutorial.xml
@@ -31,7 +31,7 @@
android:layout_marginTop="6dp"
android:layout_marginBottom="0dp"
android:gravity="center_horizontal"
- android:src="@drawable/one_handed_tutorial"
+ android:src="@drawable/one_handed_tutorial_icon"
android:scaleType="centerInside" />
<TextView
@@ -45,7 +45,6 @@
android:fontFamily="google-sans-medium"
android:text="@string/one_handed_tutorial_title"
android:textSize="16sp"
- android:textStyle="bold"
android:textColor="@android:color/white"/>
<TextView
@@ -54,8 +53,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:layout_marginBottom="0dp"
- android:layout_marginStart="46dp"
- android:layout_marginEnd="46dp"
+ android:layout_marginStart="60dp"
+ android:layout_marginEnd="60dp"
android:gravity="center_horizontal"
android:fontFamily="roboto-regular"
android:text="@string/one_handed_tutorial_description"
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index c16041d..8056d15 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -46,7 +46,7 @@
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Үстүнкү экранды 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ылдыйкы экранды толук экран режимине өткөрүү"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Бир кол режимин колдонуу"</string>
- <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Чыгуу үчүн экранды ылдый жагынан өйдө көздөй сүрүңүз же колдонмонун өйдө жагын басыңыз"</string>
+ <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Чыгуу үчүн экранды ылдый жагынан өйдө сүрүңүз же колдонмонун өйдө жагын басыңыз"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Бир кол режимин баштоо"</string>
<string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Бир кол режиминен чыгуу"</string>
<string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> калкып чыкма билдирмелер жөндөөлөрү"</string>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index d460195..36b8923 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -45,6 +45,7 @@
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.SurfaceControl;
+import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
@@ -205,6 +206,7 @@
* between bubble activities without needing both to be alive at the same time.
*/
private SurfaceView mAnimatingOutSurfaceView;
+ private boolean mAnimatingOutSurfaceReady;
/** Container for the animating-out SurfaceView. */
private FrameLayout mAnimatingOutSurfaceContainer;
@@ -808,6 +810,20 @@
mAnimatingOutSurfaceView.setZOrderOnTop(true);
mAnimatingOutSurfaceView.setCornerRadius(mCornerRadius);
mAnimatingOutSurfaceView.setLayoutParams(new ViewGroup.LayoutParams(0, 0));
+ mAnimatingOutSurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
+ @Override
+ public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {}
+
+ @Override
+ public void surfaceCreated(SurfaceHolder surfaceHolder) {
+ mAnimatingOutSurfaceReady = true;
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
+ mAnimatingOutSurfaceReady = false;
+ }
+ });
mAnimatingOutSurfaceContainer.addView(mAnimatingOutSurfaceView);
mAnimatingOutSurfaceContainer.setPadding(
@@ -2652,7 +2668,7 @@
return;
}
- if (!mIsExpanded) {
+ if (!mIsExpanded || !mAnimatingOutSurfaceReady) {
onComplete.accept(false);
return;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index 6f63369..ba59e07 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -33,6 +33,7 @@
import android.view.InsetsSource;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.WindowInsets;
@@ -198,6 +199,7 @@
public class PerDisplay {
final int mDisplayId;
final InsetsState mInsetsState = new InsetsState();
+ final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
protected final DisplayWindowInsetsControllerImpl mInsetsControllerImpl =
new DisplayWindowInsetsControllerImpl();
InsetsSourceControl mImeSourceControl = null;
@@ -327,8 +329,10 @@
*/
private void setVisibleDirectly(boolean visible) {
mInsetsState.getSource(InsetsState.ITYPE_IME).setVisible(visible);
+ mRequestedVisibilities.setVisibility(InsetsState.ITYPE_IME, visible);
try {
- mWmService.modifyDisplayWindowInsets(mDisplayId, mInsetsState);
+ mWmService.updateDisplayWindowRequestedVisibilities(mDisplayId,
+ mRequestedVisibilities);
} catch (RemoteException e) {
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index 9bcc3ac..5b9d7b80 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -151,10 +151,8 @@
final Rect rightHitRegion = new Rect();
final Rect rightDrawRegion = bottomOrRightBounds;
- displayRegion.splitVertically(leftHitRegion, fullscreenHitRegion, rightHitRegion);
+ displayRegion.splitVertically(leftHitRegion, rightHitRegion);
- mTargets.add(
- new Target(TYPE_FULLSCREEN, fullscreenHitRegion, fullscreenDrawRegion));
mTargets.add(new Target(TYPE_SPLIT_LEFT, leftHitRegion, leftDrawRegion));
mTargets.add(new Target(TYPE_SPLIT_RIGHT, rightHitRegion, rightDrawRegion));
@@ -165,10 +163,8 @@
final Rect bottomDrawRegion = bottomOrRightBounds;
displayRegion.splitHorizontally(
- topHitRegion, fullscreenHitRegion, bottomHitRegion);
+ topHitRegion, bottomHitRegion);
- mTargets.add(
- new Target(TYPE_FULLSCREEN, fullscreenHitRegion, fullscreenDrawRegion));
mTargets.add(new Target(TYPE_SPLIT_TOP, topHitRegion, topDrawRegion));
mTargets.add(new Target(TYPE_SPLIT_BOTTOM, bottomHitRegion, bottomDrawRegion));
}
@@ -269,7 +265,6 @@
* Updates the session data based on the current state of the system.
*/
void update() {
-
List<ActivityManager.RunningTaskInfo> tasks =
mActivityTaskManager.getTasks(1, false /* filterOnlyVisibleRecents */);
if (!tasks.isEmpty()) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java
index 481b948..3ccb9e7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java
@@ -20,7 +20,6 @@
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Rect;
-import android.util.Log;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.window.DisplayAreaAppearedInfo;
@@ -30,7 +29,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
-import androidx.core.content.ContextCompat;
import com.android.internal.annotations.GuardedBy;
import com.android.wm.shell.R;
@@ -48,14 +46,17 @@
public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer
implements OneHandedTransitionCallback {
private static final String TAG = "OneHandedBackgroundPanelOrganizer";
+ private static final int THEME_COLOR_OFFSET = 10;
+ private final Context mContext;
private final Object mLock = new Object();
private final SurfaceSession mSurfaceSession = new SurfaceSession();
- private final float[] mDefaultColor;
private final Executor mMainExecutor;
private final OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory
mSurfaceControlTransactionFactory;
+ private float[] mDefaultColor;
+
/**
* The background to distinguish the boundary of translated windows and empty region when
* one handed mode triggered.
@@ -88,15 +89,14 @@
public OneHandedBackgroundPanelOrganizer(Context context, DisplayLayout displayLayout,
Executor executor) {
super(executor);
+ mContext = context;
// Ensure the mBkgBounds is portrait, due to OHM only support on portrait
if (displayLayout.height() > displayLayout.width()) {
mBkgBounds = new Rect(0, 0, displayLayout.width(), displayLayout.height());
} else {
mBkgBounds = new Rect(0, 0, displayLayout.height(), displayLayout.width());
}
- final int defaultColor = ContextCompat.getColor(context, R.color.GM2_grey_800);
- mDefaultColor = new float[]{Color.red(defaultColor) / 255.0f,
- Color.green(defaultColor) / 255.0f, Color.blue(defaultColor) / 255.0f};
+ updateThemeColors();
mMainExecutor = executor;
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
}
@@ -170,7 +170,6 @@
}
if (getBackgroundSurface() == null) {
- Log.w(TAG, "mBackgroundSurface is null !");
return;
}
@@ -201,6 +200,30 @@
}
}
+ /**
+ * onConfigurationChanged events for updating tutorial text.
+ */
+ public void onConfigurationChanged() {
+ synchronized (mLock) {
+ if (mBackgroundSurface == null) {
+ getBackgroundSurface();
+ } else {
+ removeBackgroundPanelLayer();
+ }
+ updateThemeColors();
+ showBackgroundPanelLayer();
+ }
+ }
+
+ private void updateThemeColors() {
+ synchronized (mLock) {
+ final int themeColor = mContext.getColor(R.color.one_handed_tutorial_background_color);
+ mDefaultColor = new float[]{(Color.red(themeColor) - THEME_COLOR_OFFSET) / 255.0f,
+ (Color.green(themeColor) - THEME_COLOR_OFFSET) / 255.0f,
+ (Color.blue(themeColor) - THEME_COLOR_OFFSET) / 255.0f};
+ }
+ }
+
void dump(@NonNull PrintWriter pw) {
final String innerPrefix = " ";
pw.println(TAG);
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 2038cff..09cde38 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
@@ -658,12 +658,13 @@
}
private void onConfigChanged(Configuration newConfig) {
- if (mTutorialHandler == null) {
+ if (mTutorialHandler == null || mBackgroundPanelOrganizer == null) {
return;
}
if (!mIsOneHandedEnabled || newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
return;
}
+ mBackgroundPanelOrganizer.onConfigurationChanged();
mTutorialHandler.onConfigurationChanged();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
index d0206a4..97e04b5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
@@ -25,8 +25,11 @@
import static com.android.wm.shell.onehanded.OneHandedState.STATE_EXITING;
import static com.android.wm.shell.onehanded.OneHandedState.STATE_NONE;
+import android.animation.ValueAnimator;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.SystemProperties;
@@ -35,9 +38,13 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
+import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
import androidx.annotation.NonNull;
+import androidx.appcompat.view.ContextThemeWrapper;
import com.android.internal.annotations.VisibleForTesting;
import com.android.wm.shell.R;
@@ -53,11 +60,14 @@
public class OneHandedTutorialHandler implements OneHandedTransitionCallback,
OneHandedState.OnStateChangedListener {
private static final String TAG = "OneHandedTutorialHandler";
- private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE =
- "persist.debug.one_handed_offset_percentage";
+ private static final String OFFSET_PERCENTAGE = "persist.debug.one_handed_offset_percentage";
+ private static final String TRANSLATE_ANIMATION_DURATION =
+ "persist.debug.one_handed_translate_animation_duration";
+ private static final float START_TRANSITION_FRACTION = 0.7f;
private final float mTutorialHeightRatio;
private final WindowManager mWindowManager;
+ private final OneHandedAnimationCallback mAnimationCallback;
private @OneHandedState.State int mCurrentState;
private int mTutorialAreaHeight;
@@ -67,7 +77,9 @@
private @Nullable View mTutorialView;
private @Nullable ViewGroup mTargetViewContainer;
- private final OneHandedAnimationCallback mAnimationCallback;
+ private float mAlphaTransitionStart;
+ private ValueAnimator mAlphaAnimator;
+ private int mAlphaAnimationDurationMs;
public OneHandedTutorialHandler(Context context, WindowManager windowManager) {
mContext = context;
@@ -75,15 +87,35 @@
final float offsetPercentageConfig = context.getResources().getFraction(
R.fraction.config_one_handed_offset, 1, 1);
final int sysPropPercentageConfig = SystemProperties.getInt(
- ONE_HANDED_MODE_OFFSET_PERCENTAGE, Math.round(offsetPercentageConfig * 100.0f));
+ OFFSET_PERCENTAGE, Math.round(offsetPercentageConfig * 100.0f));
mTutorialHeightRatio = sysPropPercentageConfig / 100.0f;
+ final int animationDuration = context.getResources().getInteger(
+ R.integer.config_one_handed_translate_animation_duration);
+ mAlphaAnimationDurationMs = SystemProperties.getInt(TRANSLATE_ANIMATION_DURATION,
+ animationDuration);
mAnimationCallback = new OneHandedAnimationCallback() {
@Override
+ public void onOneHandedAnimationCancel(
+ OneHandedAnimationController.OneHandedTransitionAnimator animator) {
+ if (mAlphaAnimator != null) {
+ mAlphaAnimator.cancel();
+ }
+ }
+
+ @Override
public void onAnimationUpdate(float xPos, float yPos) {
if (!isAttached()) {
return;
}
- mTargetViewContainer.setTranslationY(yPos - mTutorialAreaHeight);
+ if (yPos < mAlphaTransitionStart) {
+ checkTransitionEnd();
+ return;
+ }
+ if (mAlphaAnimator == null || mAlphaAnimator.isStarted()
+ || mAlphaAnimator.isRunning()) {
+ return;
+ }
+ mAlphaAnimator.start();
}
};
}
@@ -94,12 +126,16 @@
switch (newState) {
case STATE_ENTERING:
createViewAndAttachToWindow(mContext);
+ updateThemeColor();
+ setupAlphaTransition(true /* isEntering */);
break;
case STATE_ACTIVE:
- case STATE_EXITING:
- // no - op
+ checkTransitionEnd();
+ setupAlphaTransition(false /* isEntering */);
break;
+ case STATE_EXITING:
case STATE_NONE:
+ checkTransitionEnd();
removeTutorialFromWindowManager();
break;
default:
@@ -119,6 +155,7 @@
mDisplayBounds = new Rect(0, 0, displayLayout.height(), displayLayout.width());
}
mTutorialAreaHeight = Math.round(mDisplayBounds.height() * mTutorialHeightRatio);
+ mAlphaTransitionStart = mTutorialAreaHeight * START_TRANSITION_FRACTION;
}
@VisibleForTesting
@@ -129,6 +166,7 @@
mTutorialView = LayoutInflater.from(context).inflate(R.layout.one_handed_tutorial, null);
mTargetViewContainer = new FrameLayout(context);
mTargetViewContainer.setClipChildren(false);
+ mTargetViewContainer.setAlpha(mCurrentState == STATE_ACTIVE ? 1.0f : 0.0f);
mTargetViewContainer.addView(mTutorialView);
mTargetViewContainer.setLayerType(LAYER_TYPE_HARDWARE, null);
@@ -192,6 +230,52 @@
removeTutorialFromWindowManager();
if (mCurrentState == STATE_ENTERING || mCurrentState == STATE_ACTIVE) {
createViewAndAttachToWindow(mContext);
+ updateThemeColor();
+ checkTransitionEnd();
+ }
+ }
+
+ private void updateThemeColor() {
+ if (mTutorialView == null) {
+ return;
+ }
+
+ final Context themedContext = new ContextThemeWrapper(mTutorialView.getContext(),
+ com.android.internal.R.style.Theme_DeviceDefault_DayNight);
+ final int textColorPrimary;
+ final int themedTextColorSecondary;
+ TypedArray ta = themedContext.obtainStyledAttributes(new int[]{
+ com.android.internal.R.attr.textColorPrimary,
+ com.android.internal.R.attr.textColorSecondary});
+ textColorPrimary = ta.getColor(0, 0);
+ themedTextColorSecondary = ta.getColor(1, 0);
+ ta.recycle();
+
+ final ImageView iconView = mTutorialView.findViewById(R.id.one_handed_tutorial_image);
+ iconView.setImageTintList(ColorStateList.valueOf(textColorPrimary));
+
+ final TextView tutorialTitle = mTutorialView.findViewById(R.id.one_handed_tutorial_title);
+ final TextView tutorialDesc = mTutorialView.findViewById(
+ R.id.one_handed_tutorial_description);
+ tutorialTitle.setTextColor(textColorPrimary);
+ tutorialDesc.setTextColor(themedTextColorSecondary);
+ }
+
+ private void setupAlphaTransition(boolean isEntering) {
+ final float start = isEntering ? 0.0f : 1.0f;
+ final float end = isEntering ? 1.0f : 0.0f;
+ mAlphaAnimator = ValueAnimator.ofFloat(start, end);
+ mAlphaAnimator.setInterpolator(new LinearInterpolator());
+ mAlphaAnimator.setDuration(mAlphaAnimationDurationMs);
+ mAlphaAnimator.addUpdateListener(
+ animator -> mTargetViewContainer.setAlpha((float) animator.getAnimatedValue()));
+ }
+
+ private void checkTransitionEnd() {
+ if (mAlphaAnimator != null && mAlphaAnimator.isRunning()) {
+ mAlphaAnimator.end();
+ mAlphaAnimator.removeAllUpdateListeners();
+ mAlphaAnimator = null;
}
}
@@ -206,5 +290,9 @@
pw.println(mDisplayBounds);
pw.print(innerPrefix + "mTutorialAreaHeight=");
pw.println(mTutorialAreaHeight);
+ pw.print(innerPrefix + "mAlphaTransitionStart=");
+ pw.println(mAlphaTransitionStart);
+ pw.print(innerPrefix + "mAlphaAnimationDurationMs=");
+ pw.println(mAlphaAnimationDurationMs);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index 200af74..05111a3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -38,6 +38,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.wm.shell.animation.Interpolators;
+import com.android.wm.shell.transition.Transitions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -617,14 +618,28 @@
setCurrentValue(bounds);
final Rect insets = computeInsets(fraction);
final float degree, x, y;
- if (rotationDelta == ROTATION_90) {
- degree = 90 * fraction;
- x = fraction * (end.right - start.left) + start.left;
- y = fraction * (end.top - start.top) + start.top;
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ if (rotationDelta == ROTATION_90) {
+ degree = 90 * (1 - fraction);
+ x = fraction * (end.left - start.left)
+ + start.left + start.right * (1 - fraction);
+ y = fraction * (end.top - start.top) + start.top;
+ } else {
+ degree = -90 * (1 - fraction);
+ x = fraction * (end.left - start.left) + start.left;
+ y = fraction * (end.top - start.top)
+ + start.top + start.bottom * (1 - fraction);
+ }
} else {
- degree = -90 * fraction;
- x = fraction * (end.left - start.left) + start.left;
- y = fraction * (end.bottom - start.top) + start.top;
+ if (rotationDelta == ROTATION_90) {
+ degree = 90 * fraction;
+ x = fraction * (end.right - start.left) + start.left;
+ y = fraction * (end.top - start.top) + start.top;
+ } else {
+ degree = -90 * fraction;
+ x = fraction * (end.left - start.left) + start.left;
+ y = fraction * (end.bottom - start.top) + start.top;
+ }
}
getSurfaceTransactionHelper()
.rotateAndScaleWithCrop(tx, leash, initialContainerRect, bounds,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
index 728794d..180e3fb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
@@ -23,6 +23,7 @@
import android.view.SurfaceControl;
import com.android.wm.shell.R;
+import com.android.wm.shell.transition.Transitions;
/**
* Abstracts the common operations on {@link SurfaceControl.Transaction} for PiP transition.
@@ -137,7 +138,8 @@
// destination are different.
final float scale = srcW <= srcH ? (float) destW / srcW : (float) destH / srcH;
final Rect crop = mTmpDestinationRect;
- crop.set(0, 0, destW, destH);
+ crop.set(0, 0, Transitions.ENABLE_SHELL_TRANSITIONS ? destH
+ : destW, Transitions.ENABLE_SHELL_TRANSITIONS ? destW : destH);
// Inverse scale for crop to fit in screen coordinates.
crop.scale(1 / scale);
crop.offset(insets.left, insets.top);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index a0d83c0..d77619a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -243,16 +243,8 @@
private @Surface.Rotation int mCurrentRotation;
/**
- * If set to {@code true}, no entering PiP transition would be kicked off and most likely
- * it's due to the fact that Launcher is handling the transition directly when swiping
- * auto PiP-able Activity to home.
- * See also {@link #startSwipePipToHome(ComponentName, ActivityInfo, PictureInPictureParams)}.
- */
- private boolean mInSwipePipToHomeTransition;
-
- /**
* An optional overlay used to mask content changing between an app in/out of PiP, only set if
- * {@link #mInSwipePipToHomeTransition} is true.
+ * {@link PipTransitionState#getInSwipePipToHomeTransition()} is true.
*/
private SurfaceControl mSwipePipToHomeOverlay;
@@ -343,7 +335,7 @@
*/
public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
PictureInPictureParams pictureInPictureParams) {
- mInSwipePipToHomeTransition = true;
+ mPipTransitionState.setInSwipePipToHomeTransition(true);
sendOnPipTransitionStarted(TRANSITION_DIRECTION_TO_PIP);
setBoundsStateForEntry(componentName, pictureInPictureParams, activityInfo);
return mPipBoundsAlgorithm.getEntryDestinationBounds();
@@ -356,7 +348,7 @@
public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds,
SurfaceControl overlay) {
// do nothing if there is no startSwipePipToHome being called before
- if (mInSwipePipToHomeTransition) {
+ if (mPipTransitionState.getInSwipePipToHomeTransition()) {
mPipBoundsState.setBounds(destinationBounds);
mSwipePipToHomeOverlay = overlay;
}
@@ -517,7 +509,7 @@
mOnDisplayIdChangeCallback.accept(info.displayId);
}
- if (mInSwipePipToHomeTransition) {
+ if (mPipTransitionState.getInSwipePipToHomeTransition()) {
if (!mWaitForFixedRotation) {
onEndOfSwipePipToHomeTransition();
} else {
@@ -626,7 +618,7 @@
private void onEndOfSwipePipToHomeTransition() {
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- mInSwipePipToHomeTransition = false;
+ mPipTransitionState.setInSwipePipToHomeTransition(false);
mSwipePipToHomeOverlay = null;
return;
}
@@ -650,7 +642,7 @@
null /* callback */, false /* withStartDelay */);
}
}, tx);
- mInSwipePipToHomeTransition = false;
+ mPipTransitionState.setInSwipePipToHomeTransition(false);
mSwipePipToHomeOverlay = null;
}
@@ -718,7 +710,7 @@
return;
}
clearWaitForFixedRotation();
- mInSwipePipToHomeTransition = false;
+ mPipTransitionState.setInSwipePipToHomeTransition(false);
mPictureInPictureParams = null;
mPipTransitionState.setTransitionState(PipTransitionState.UNDEFINED);
// Re-set the PIP bounds to none.
@@ -793,7 +785,7 @@
return;
}
if (mPipTransitionState.getTransitionState() == PipTransitionState.TASK_APPEARED) {
- if (mInSwipePipToHomeTransition) {
+ if (mPipTransitionState.getInSwipePipToHomeTransition()) {
onEndOfSwipePipToHomeTransition();
} else {
// Schedule a regular animation to ensure all the callbacks are still being sent.
@@ -859,10 +851,12 @@
// Skip this entirely if that's the case.
final boolean waitForFixedRotationOnEnteringPip = mWaitForFixedRotation
&& (mPipTransitionState.getTransitionState() != PipTransitionState.ENTERED_PIP);
- if ((mInSwipePipToHomeTransition || waitForFixedRotationOnEnteringPip) && fromRotation) {
+ if ((mPipTransitionState.getInSwipePipToHomeTransition()
+ || waitForFixedRotationOnEnteringPip) && fromRotation) {
if (DEBUG) {
Log.d(TAG, "Skip onMovementBoundsChanged on rotation change"
- + " mInSwipePipToHomeTransition=" + mInSwipePipToHomeTransition
+ + " InSwipePipToHomeTransition="
+ + mPipTransitionState.getInSwipePipToHomeTransition()
+ " mWaitForFixedRotation=" + mWaitForFixedRotation
+ " getTransitionState=" + mPipTransitionState.getTransitionState());
}
@@ -1383,11 +1377,20 @@
final ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 0.0f);
animator.setDuration(mCrossFadeAnimationDuration);
animator.addUpdateListener(animation -> {
- final float alpha = (float) animation.getAnimatedValue();
- final SurfaceControl.Transaction transaction =
- mSurfaceControlTransactionFactory.getTransaction();
- transaction.setAlpha(surface, alpha);
- transaction.apply();
+ if (mPipTransitionState.getTransitionState() == PipTransitionState.UNDEFINED) {
+ // Could happen if onTaskVanished happens during the animation since we may have
+ // set a start delay on this animation.
+ Log.d(TAG, "Task vanished, skip fadeOutAndRemoveOverlay");
+ animation.removeAllListeners();
+ animation.removeAllUpdateListeners();
+ animation.cancel();
+ } else {
+ final float alpha = (float) animation.getAnimatedValue();
+ final SurfaceControl.Transaction transaction =
+ mSurfaceControlTransactionFactory.getTransaction();
+ transaction.setAlpha(surface, alpha);
+ transaction.apply();
+ }
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -1400,6 +1403,10 @@
}
private void removeContentOverlay(SurfaceControl surface, Runnable callback) {
+ if (mPipTransitionState.getTransitionState() == PipTransitionState.UNDEFINED) {
+ // Avoid double removal, which is fatal.
+ return;
+ }
final SurfaceControl.Transaction tx =
mSurfaceControlTransactionFactory.getTransaction();
tx.remove(surface);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 18153e3..ae17a93 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -18,6 +18,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.util.RotationUtils.deltaRotation;
import static android.view.WindowManager.TRANSIT_PIP;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
@@ -151,7 +152,8 @@
mPipTransitionState.setTransitionState(PipTransitionState.ENTERING_PIP);
mFinishCallback = finishCallback;
return startEnterAnimation(enterPip.getTaskInfo(), enterPip.getLeash(),
- startTransaction, finishTransaction);
+ startTransaction, finishTransaction, enterPip.getStartRotation(),
+ enterPip.getEndRotation());
}
@Nullable
@@ -208,7 +210,8 @@
private boolean startEnterAnimation(final TaskInfo taskInfo, final SurfaceControl leash,
final SurfaceControl.Transaction startTransaction,
- final SurfaceControl.Transaction finishTransaction) {
+ final SurfaceControl.Transaction finishTransaction,
+ final int startRotation, final int endRotation) {
setBoundsStateForEntry(taskInfo.topActivity, taskInfo.pictureInPictureParams,
taskInfo.topActivityInfo);
final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
@@ -216,7 +219,8 @@
PipAnimationController.PipTransitionAnimator animator;
finishTransaction.setPosition(leash, destinationBounds.left, destinationBounds.top);
if (taskInfo.pictureInPictureParams != null
- && taskInfo.pictureInPictureParams.isAutoEnterEnabled()) {
+ && taskInfo.pictureInPictureParams.isAutoEnterEnabled()
+ && mPipTransitionState.getInSwipePipToHomeTransition()) {
mOneShotAnimationType = ANIM_TYPE_BOUNDS;
// PiP menu is attached late in the process here to avoid any artifacts on the leash
@@ -234,13 +238,21 @@
mFinishCallback = null;
return true;
}
+
+ int rotationDelta = deltaRotation(endRotation, startRotation);
+ if (rotationDelta != Surface.ROTATION_0) {
+ Matrix tmpTransform = new Matrix();
+ tmpTransform.postRotate(rotationDelta == Surface.ROTATION_90
+ ? Surface.ROTATION_270 : Surface.ROTATION_90);
+ startTransaction.setMatrix(leash, tmpTransform, new float[9]);
+ }
if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
final Rect sourceHintRect =
PipBoundsAlgorithm.getValidSourceHintRect(
taskInfo.pictureInPictureParams, currentBounds);
animator = mPipAnimationController.getAnimator(taskInfo, leash, currentBounds,
currentBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP,
- 0 /* startingAngle */, Surface.ROTATION_0);
+ 0 /* startingAngle */, rotationDelta);
} else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
startTransaction.setAlpha(leash, 0f);
// PiP menu is attached late in the process here to avoid any artifacts on the leash
@@ -258,6 +270,7 @@
.setPipAnimationCallback(mPipAnimationCallback)
.setDuration(mEnterExitAnimationDuration)
.start();
+
return true;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
index d23aada..85e56b7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
@@ -17,6 +17,9 @@
package com.android.wm.shell.pip;
import android.annotation.IntDef;
+import android.app.PictureInPictureParams;
+import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -34,6 +37,15 @@
public static final int ENTERED_PIP = 4;
public static final int EXITING_PIP = 5;
+ /**
+ * If set to {@code true}, no entering PiP transition would be kicked off and most likely
+ * it's due to the fact that Launcher is handling the transition directly when swiping
+ * auto PiP-able Activity to home.
+ * See also {@link PipTaskOrganizer#startSwipePipToHome(ComponentName, ActivityInfo,
+ * PictureInPictureParams)}.
+ */
+ private boolean mInSwipePipToHomeTransition;
+
// Not a complete set of states but serves what we want right now.
@IntDef(prefix = { "TRANSITION_STATE_" }, value = {
UNDEFINED,
@@ -65,6 +77,13 @@
&& mState != EXITING_PIP;
}
+ public void setInSwipePipToHomeTransition(boolean inSwipePipToHomeTransition) {
+ mInSwipePipToHomeTransition = inSwipePipToHomeTransition;
+ }
+
+ public boolean getInSwipePipToHomeTransition() {
+ return mInSwipePipToHomeTransition;
+ }
/**
* Resize request can be initiated in other component, ignore if we are no longer in PIP,
* still waiting for animation or we're exiting from it.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
index 1da9577..82092ac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
@@ -158,14 +158,16 @@
@Override
public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) {
- mMainExecutor.executeDelayed(() -> {
- mMotionHelper.notifyDismissalPending();
- mMotionHelper.animateDismiss();
- hideDismissTargetMaybe();
+ if (mEnableDismissDragToEdge) {
+ mMainExecutor.executeDelayed(() -> {
+ mMotionHelper.notifyDismissalPending();
+ mMotionHelper.animateDismiss();
+ hideDismissTargetMaybe();
- mPipUiEventLogger.log(
- PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_DRAG_TO_REMOVE);
- }, 0);
+ mPipUiEventLogger.log(
+ PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_DRAG_TO_REMOVE);
+ }, 0);
+ }
}
});
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index d6afeba..e86462f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -17,10 +17,13 @@
package com.android.wm.shell.splitscreen;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.common.split.SplitLayout.SplitPosition;
+import java.util.concurrent.Executor;
+
/**
* Interface to engage split-screen feature.
* TODO: Figure out which of these are actually needed outside of the Shell
@@ -53,10 +56,18 @@
/** Callback interface for listening to changes in a split-screen stage. */
interface SplitScreenListener {
- void onStagePositionChanged(@StageType int stage, @SplitPosition int position);
- void onTaskStageChanged(int taskId, @StageType int stage, boolean visible);
+ default void onStagePositionChanged(@StageType int stage, @SplitPosition int position) {}
+ default void onTaskStageChanged(int taskId, @StageType int stage, boolean visible) {}
+ default void onSplitVisibilityChanged(boolean visible) {}
}
+ /** Registers listener that gets split screen callback. */
+ void registerSplitScreenListener(@NonNull SplitScreenListener listener,
+ @NonNull Executor executor);
+
+ /** Unregisters listener that gets split screen callback. */
+ void unregisterSplitScreenListener(@NonNull SplitScreenListener listener);
+
/**
* Returns a binder that can be passed to an external process to manipulate SplitScreen.
*/
@@ -70,6 +81,12 @@
*/
void onKeyguardOccludedChanged(boolean occluded);
+ /**
+ * Called when the visibility of the keyguard changes.
+ * @param showing Indicates if the keyguard is now visible.
+ */
+ void onKeyguardVisibilityChanged(boolean showing);
+
/** Get a string representation of a stage type */
static String stageTypeToString(@StageType int stage) {
switch (stage) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index aca545b4..7804c77 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -36,6 +36,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.util.ArrayMap;
import android.util.Slog;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.RemoteAnimationAdapter;
@@ -64,6 +65,7 @@
import com.android.wm.shell.transition.Transitions;
import java.io.PrintWriter;
+import java.util.concurrent.Executor;
/**
* Class manages split-screen multitasking mode and implements the main interface
@@ -170,6 +172,10 @@
mStageCoordinator.onKeyguardOccludedChanged(occluded);
}
+ public void onKeyguardVisibilityChanged(boolean showing) {
+ mStageCoordinator.onKeyguardVisibilityChanged(showing);
+ }
+
public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
mStageCoordinator.exitSplitScreenOnHide(exitSplitScreenOnHide);
}
@@ -249,14 +255,17 @@
});
return;
}
- }
- for (int i = 0; i < apps.length; ++i) {
- if (apps[i].mode == MODE_OPENING) {
- t.show(apps[i].leash);
+ } else {
+ for (int i = 0; i < apps.length; ++i) {
+ if (apps[i].mode == MODE_OPENING) {
+ t.show(apps[i].leash);
+ }
}
}
RemoteAnimationTarget divider = mStageCoordinator.getDividerBarLegacyTarget();
- t.show(divider.leash);
+ if (divider.leash != null) {
+ t.show(divider.leash);
+ }
t.apply();
if (cancelled) return;
try {
@@ -290,6 +299,38 @@
@ExternalThread
private class SplitScreenImpl implements SplitScreen {
private ISplitScreenImpl mISplitScreen;
+ private final ArrayMap<SplitScreenListener, Executor> mExecutors = new ArrayMap<>();
+ private final SplitScreen.SplitScreenListener mListener = new SplitScreenListener() {
+ @Override
+ public void onStagePositionChanged(int stage, int position) {
+ for (int i = 0; i < mExecutors.size(); i++) {
+ final int index = i;
+ mExecutors.valueAt(index).execute(() -> {
+ mExecutors.keyAt(index).onStagePositionChanged(stage, position);
+ });
+ }
+ }
+
+ @Override
+ public void onTaskStageChanged(int taskId, int stage, boolean visible) {
+ for (int i = 0; i < mExecutors.size(); i++) {
+ final int index = i;
+ mExecutors.valueAt(index).execute(() -> {
+ mExecutors.keyAt(index).onTaskStageChanged(taskId, stage, visible);
+ });
+ }
+ }
+
+ @Override
+ public void onSplitVisibilityChanged(boolean visible) {
+ for (int i = 0; i < mExecutors.size(); i++) {
+ final int index = i;
+ mExecutors.valueAt(index).execute(() -> {
+ mExecutors.keyAt(index).onSplitVisibilityChanged(visible);
+ });
+ }
+ }
+ };
@Override
public ISplitScreen createExternalInterface() {
@@ -306,6 +347,41 @@
SplitScreenController.this.onKeyguardOccludedChanged(occluded);
});
}
+
+ @Override
+ public void registerSplitScreenListener(SplitScreenListener listener, Executor executor) {
+ if (mExecutors.containsKey(listener)) return;
+
+ mMainExecutor.execute(() -> {
+ if (mExecutors.size() == 0) {
+ SplitScreenController.this.registerSplitScreenListener(mListener);
+ }
+
+ mExecutors.put(listener, executor);
+ });
+
+ executor.execute(() -> {
+ mStageCoordinator.sendStatusToListener(listener);
+ });
+ }
+
+ @Override
+ public void unregisterSplitScreenListener(SplitScreenListener listener) {
+ mMainExecutor.execute(() -> {
+ mExecutors.remove(listener);
+
+ if (mExecutors.size() == 0) {
+ SplitScreenController.this.unregisterSplitScreenListener(mListener);
+ }
+ });
+ }
+
+ @Override
+ public void onKeyguardVisibilityChanged(boolean showing) {
+ mMainExecutor.execute(() -> {
+ SplitScreenController.this.onKeyguardVisibilityChanged(showing);
+ });
+ }
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 81ce2b7..962b5d5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -136,7 +136,10 @@
/** Whether the device is supporting legacy split or not. */
private boolean mUseLegacySplit;
- @SplitScreen.StageType int mDismissTop = NO_DISMISS;
+ @SplitScreen.StageType private int mDismissTop = NO_DISMISS;
+
+ /** The target stage to dismiss to when unlock after folded. */
+ @SplitScreen.StageType private int mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
private final Runnable mOnTransitionAnimationComplete = () -> {
// If still playing, let it finish.
@@ -443,6 +446,13 @@
mKeyguardOccluded = occluded;
}
+ void onKeyguardVisibilityChanged(boolean showing) {
+ if (!showing && mMainStage.isActive()
+ && mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
+ exitSplitScreen(mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage);
+ }
+ }
+
void exitSplitScreen() {
exitSplitScreen(null /* childrenToTop */);
}
@@ -458,6 +468,7 @@
mTaskOrganizer.applyTransaction(wct);
// Reset divider position.
mSplitLayout.resetDividerPosition();
+ mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
}
/**
@@ -501,16 +512,21 @@
void registerSplitScreenListener(SplitScreen.SplitScreenListener listener) {
if (mListeners.contains(listener)) return;
mListeners.add(listener);
- listener.onStagePositionChanged(STAGE_TYPE_MAIN, getMainStagePosition());
- listener.onStagePositionChanged(STAGE_TYPE_SIDE, getSideStagePosition());
- mSideStage.onSplitScreenListenerRegistered(listener, STAGE_TYPE_SIDE);
- mMainStage.onSplitScreenListenerRegistered(listener, STAGE_TYPE_MAIN);
+ sendStatusToListener(listener);
}
void unregisterSplitScreenListener(SplitScreen.SplitScreenListener listener) {
mListeners.remove(listener);
}
+ void sendStatusToListener(SplitScreen.SplitScreenListener listener) {
+ listener.onStagePositionChanged(STAGE_TYPE_MAIN, getMainStagePosition());
+ listener.onStagePositionChanged(STAGE_TYPE_SIDE, getSideStagePosition());
+ listener.onSplitVisibilityChanged(isSplitScreenVisible());
+ mSideStage.onSplitScreenListenerRegistered(listener, STAGE_TYPE_SIDE);
+ mMainStage.onSplitScreenListenerRegistered(listener, STAGE_TYPE_MAIN);
+ }
+
private void sendOnStagePositionChanged() {
for (int i = mListeners.size() - 1; i >= 0; --i) {
final SplitScreen.SplitScreenListener l = mListeners.get(i);
@@ -535,6 +551,13 @@
}
}
+ private void sendSplitVisibilityChanged() {
+ for (int i = mListeners.size() - 1; i >= 0; --i) {
+ final SplitScreen.SplitScreenListener l = mListeners.get(i);
+ l.onSplitVisibilityChanged(mDividerVisible);
+ }
+ }
+
private void onStageRootTaskAppeared(StageListenerImpl stageListener) {
if (mMainStageListener.mHasRootTask && mSideStageListener.mHasRootTask) {
mUseLegacySplit = mContext.getResources().getBoolean(R.bool.config_useLegacySplit);
@@ -574,6 +597,7 @@
} else {
mSplitLayout.release();
}
+ sendSplitVisibilityChanged();
}
private void onStageVisibilityChanged(StageListenerImpl stageListener) {
@@ -620,22 +644,9 @@
}
mSyncQueue.runInSync(t -> {
- final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
final SurfaceControl sideStageLeash = mSideStage.mRootLeash;
final SurfaceControl mainStageLeash = mMainStage.mRootLeash;
- if (dividerLeash != null) {
- if (mDividerVisible) {
- t.show(dividerLeash)
- .setLayer(dividerLeash, Integer.MAX_VALUE)
- .setPosition(dividerLeash,
- mSplitLayout.getDividerBounds().left,
- mSplitLayout.getDividerBounds().top);
- } else {
- t.hide(dividerLeash);
- }
- }
-
if (sideStageVisible) {
final Rect sideStageBounds = getSideStageBounds();
t.show(sideStageLeash)
@@ -662,9 +673,30 @@
} else {
t.hide(mainStageLeash);
}
+
+ applyDividerVisibility(t);
});
}
+ private void applyDividerVisibility(SurfaceControl.Transaction t) {
+ final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
+ if (dividerLeash == null) {
+ return;
+ }
+
+ if (mDividerVisible) {
+ t.show(dividerLeash)
+ .setLayer(dividerLeash, Integer.MAX_VALUE)
+ .setPosition(dividerLeash,
+ mSplitLayout.getDividerBounds().left,
+ mSplitLayout.getDividerBounds().top);
+ } else {
+ t.hide(dividerLeash);
+ }
+
+ }
+
+
private void onStageHasChildrenChanged(StageListenerImpl stageListener) {
final boolean hasChildren = stageListener.mHasChildren;
final boolean isSideStage = stageListener == mSideStageListener;
@@ -782,12 +814,18 @@
&& mSplitLayout.updateConfiguration(mDisplayAreaInfo.configuration)
&& mMainStage.isActive()) {
onBoundsChanged(mSplitLayout);
+ mSyncQueue.runInSync(t -> applyDividerVisibility(t));
}
}
private void onFoldedStateChanged(boolean folded) {
- if (folded && mMainStage.isActive()) {
- exitSplitScreen(mMainStage);
+ mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
+ if (!folded) return;
+
+ if (mMainStage.isFocused()) {
+ mTopStageAfterFoldDismiss = STAGE_TYPE_MAIN;
+ } else if (mSideStage.isFocused()) {
+ mTopStageAfterFoldDismiss = STAGE_TYPE_SIDE;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 4f73fee..c47353a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -97,6 +97,15 @@
return mChildrenTaskInfo.contains(taskId);
}
+ /** @return {@code true} if this listener contains the currently focused task. */
+ boolean isFocused() {
+ if (mRootTaskInfo.isFocused) return true;
+ for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
+ if (mChildrenTaskInfo.valueAt(i).isFocused) return true;
+ }
+ return false;
+ }
+
@Override
@CallSuper
public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 56ad2be..dff5577 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -23,6 +23,7 @@
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
import android.annotation.ColorInt;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.app.ActivityThread;
import android.content.BroadcastReceiver;
@@ -64,6 +65,7 @@
import java.util.List;
import java.util.function.Consumer;
+import java.util.function.IntPredicate;
import java.util.function.IntSupplier;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
@@ -132,7 +134,6 @@
* @param splashScreenViewConsumer Receiving the SplashScreenView object, which will also be
* executed on splash screen thread. Note that the view can be
* null if failed.
- * @param bgColorConsumer Receiving the background color once it's estimated complete.
*/
void createContentView(Context context, @StartingWindowType int suggestType, ActivityInfo info,
int taskId, Consumer<SplashScreenView> splashScreenViewConsumer) {
@@ -209,9 +210,9 @@
}
private static int estimateWindowBGColor(Drawable themeBGDrawable) {
- final DrawableColorTester themeBGTester =
- new DrawableColorTester(themeBGDrawable, true /* filterTransparent */);
- if (themeBGTester.nonTransparentRatio() == 0) {
+ final DrawableColorTester themeBGTester = new DrawableColorTester(
+ themeBGDrawable, DrawableColorTester.TRANSPARENT_FILTER /* filterType */);
+ if (themeBGTester.passFilterRatio() == 0) {
// the window background is transparent, unable to draw
Slog.w(TAG, "Window background is transparent, fill background with black color");
return getSystemBGColor();
@@ -414,7 +415,8 @@
final ColorCache.IconColor iconColor = mColorCache.getIconColor(
mActivityInfo.packageName, mActivityInfo.getIconResource(),
mLastPackageContextConfigHash,
- () -> new DrawableColorTester(iconForeground, true /* filterTransparent */),
+ () -> new DrawableColorTester(iconForeground,
+ DrawableColorTester.TRANSLUCENT_FILTER /* filterType */),
() -> new DrawableColorTester(adaptiveIconDrawable.getBackground()));
if (DEBUG) {
@@ -443,7 +445,7 @@
// Reference AdaptiveIcon description, outer is 108 and inner is 72, so we
// scale by 192/160 if we only draw adaptiveIcon's foreground.
final float noBgScale =
- iconColor.mFgNonTransparentRatio < ENLARGE_FOREGROUND_ICON_THRESHOLD
+ iconColor.mFgNonTranslucentRatio < ENLARGE_FOREGROUND_ICON_THRESHOLD
? NO_BACKGROUND_SCALE : 1f;
// Using AdaptiveIconDrawable here can help keep the shape consistent with the
// current settings.
@@ -545,13 +547,26 @@
}
private static class DrawableColorTester {
+ private static final int NO_ALPHA_FILTER = 0;
+ // filter out completely invisible pixels
+ private static final int TRANSPARENT_FILTER = 1;
+ // filter out translucent and invisible pixels
+ private static final int TRANSLUCENT_FILTER = 2;
+
+ @IntDef(flag = true, value = {
+ NO_ALPHA_FILTER,
+ TRANSPARENT_FILTER,
+ TRANSLUCENT_FILTER
+ })
+ private @interface QuantizerFilterType {}
+
private final ColorTester mColorChecker;
DrawableColorTester(Drawable drawable) {
- this(drawable, false /* filterTransparent */);
+ this(drawable, NO_ALPHA_FILTER /* filterType */);
}
- DrawableColorTester(Drawable drawable, boolean filterTransparent) {
+ DrawableColorTester(Drawable drawable, @QuantizerFilterType int filterType) {
// Some applications use LayerDrawable for their windowBackground. To ensure that we
// only get the real background, so that the color is not affected by the alpha of the
// upper layer, try to get the lower layer here. This can also speed up the calculation.
@@ -570,12 +585,12 @@
} else {
mColorChecker = drawable instanceof ColorDrawable
? new SingleColorTester((ColorDrawable) drawable)
- : new ComplexDrawableTester(drawable, filterTransparent);
+ : new ComplexDrawableTester(drawable, filterType);
}
}
- public float nonTransparentRatio() {
- return mColorChecker.nonTransparentRatio();
+ public float passFilterRatio() {
+ return mColorChecker.passFilterRatio();
}
public boolean isComplexColor() {
@@ -594,7 +609,7 @@
* A help class to check the color information from a Drawable.
*/
private interface ColorTester {
- float nonTransparentRatio();
+ float passFilterRatio();
boolean isComplexColor();
@@ -622,7 +637,7 @@
}
@Override
- public float nonTransparentRatio() {
+ public float passFilterRatio() {
final int alpha = mColorDrawable.getAlpha();
return (float) (alpha / 255);
}
@@ -651,15 +666,21 @@
private static final int MAX_BITMAP_SIZE = 40;
private final Palette mPalette;
private final boolean mFilterTransparent;
- private static final TransparentFilterQuantizer TRANSPARENT_FILTER_QUANTIZER =
- new TransparentFilterQuantizer();
+ private static final AlphaFilterQuantizer ALPHA_FILTER_QUANTIZER =
+ new AlphaFilterQuantizer();
- ComplexDrawableTester(Drawable drawable, boolean filterTransparent) {
+ /**
+ * @param drawable The test target.
+ * @param filterType Targeting to filter out transparent or translucent pixels,
+ * this would be needed if want to check
+ * {@link #passFilterRatio()}, also affecting the estimated result
+ * of the dominant color.
+ */
+ ComplexDrawableTester(Drawable drawable, @QuantizerFilterType int filterType) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "ComplexDrawableTester");
final Rect initialBounds = drawable.copyBounds();
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
-
// Some drawables do not have intrinsic dimensions
if (width <= 0 || height <= 0) {
width = MAX_BITMAP_SIZE;
@@ -680,9 +701,10 @@
// The Palette API will ignore Alpha, so it cannot handle transparent pixels, but
// sometimes we will need this information to know if this Drawable object is
// transparent.
- mFilterTransparent = filterTransparent;
+ mFilterTransparent = filterType != NO_ALPHA_FILTER;
if (mFilterTransparent) {
- builder = new Palette.Builder(bitmap, TRANSPARENT_FILTER_QUANTIZER)
+ ALPHA_FILTER_QUANTIZER.setFilter(filterType);
+ builder = new Palette.Builder(bitmap, ALPHA_FILTER_QUANTIZER)
.maximumColorCount(5);
} else {
builder = new Palette.Builder(bitmap, null)
@@ -694,8 +716,8 @@
}
@Override
- public float nonTransparentRatio() {
- return mFilterTransparent ? TRANSPARENT_FILTER_QUANTIZER.mNonTransparentRatio : 1;
+ public float passFilterRatio() {
+ return mFilterTransparent ? ALPHA_FILTER_QUANTIZER.mPassFilterRatio : 1;
}
@Override
@@ -726,17 +748,34 @@
return true;
}
- private static class TransparentFilterQuantizer implements Quantizer {
+ private static class AlphaFilterQuantizer implements Quantizer {
private static final int NON_TRANSPARENT = 0xFF000000;
private final Quantizer mInnerQuantizer = new VariationalKMeansQuantizer();
- private float mNonTransparentRatio;
+ private final IntPredicate mTransparentFilter = i -> (i & NON_TRANSPARENT) != 0;
+ private final IntPredicate mTranslucentFilter = i ->
+ (i & NON_TRANSPARENT) == NON_TRANSPARENT;
+
+ private IntPredicate mFilter = mTransparentFilter;
+ private float mPassFilterRatio;
+
+ void setFilter(@QuantizerFilterType int filterType) {
+ switch (filterType) {
+ case TRANSLUCENT_FILTER:
+ mFilter = mTranslucentFilter;
+ break;
+ case TRANSPARENT_FILTER:
+ default:
+ mFilter = mTransparentFilter;
+ break;
+ }
+ }
@Override
public void quantize(final int[] pixels, final int maxColors) {
- mNonTransparentRatio = 0;
+ mPassFilterRatio = 0;
int realSize = 0;
for (int i = pixels.length - 1; i > 0; i--) {
- if ((pixels[i] & NON_TRANSPARENT) != 0) {
+ if (mFilter.test(pixels[i])) {
realSize++;
}
}
@@ -747,11 +786,11 @@
mInnerQuantizer.quantize(pixels, maxColors);
return;
}
- mNonTransparentRatio = (float) realSize / pixels.length;
+ mPassFilterRatio = (float) realSize / pixels.length;
final int[] samplePixels = new int[realSize];
int rowIndex = 0;
for (int i = pixels.length - 1; i > 0; i--) {
- if ((pixels[i] & NON_TRANSPARENT) == NON_TRANSPARENT) {
+ if (mFilter.test(pixels[i])) {
samplePixels[rowIndex] = pixels[i];
rowIndex++;
}
@@ -810,16 +849,16 @@
final int mBgColor;
final boolean mIsBgComplex;
final boolean mIsBgGrayscale;
- final float mFgNonTransparentRatio;
+ final float mFgNonTranslucentRatio;
IconColor(int hash, int fgColor, int bgColor, boolean isBgComplex,
- boolean isBgGrayscale, float fgNonTransparentRatio) {
+ boolean isBgGrayscale, float fgNonTranslucnetRatio) {
super(hash);
mFgColor = fgColor;
mBgColor = bgColor;
mIsBgComplex = isBgComplex;
mIsBgGrayscale = isBgGrayscale;
- mFgNonTransparentRatio = fgNonTransparentRatio;
+ mFgNonTranslucentRatio = fgNonTranslucnetRatio;
}
}
@@ -905,7 +944,7 @@
final DrawableColorTester bgTester = bgColorTesterSupplier.get();
final IconColor iconColor = new IconColor(hash, fgTester.getDominateColor(),
bgTester.getDominateColor(), bgTester.isComplexColor(), bgTester.isGrayscale(),
- fgTester.nonTransparentRatio());
+ fgTester.passFilterRatio());
colors.mIconColors[leastUsedIndex[0]] = iconColor;
return iconColor;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 243751fe..fc7c86d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -168,16 +168,14 @@
void addSplashScreenStartingWindow(StartingWindowInfo windowInfo, IBinder appToken,
@StartingWindowType int suggestType) {
final RunningTaskInfo taskInfo = windowInfo.taskInfo;
- final ActivityInfo activityInfo = taskInfo.topActivityInfo;
- if (activityInfo == null) {
+ final ActivityInfo activityInfo = windowInfo.targetActivityInfo != null
+ ? windowInfo.targetActivityInfo
+ : taskInfo.topActivityInfo;
+ if (activityInfo == null || activityInfo.packageName == null) {
return;
}
final int displayId = taskInfo.displayId;
- if (activityInfo.packageName == null) {
- return;
- }
-
final int taskId = taskInfo.taskId;
Context context = mContext;
// replace with the default theme if the application didn't set
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index 6052d3d..7d011e6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -72,6 +72,7 @@
import android.view.InputChannel;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.View;
@@ -205,7 +206,7 @@
final SurfaceControl surfaceControl = new SurfaceControl();
final ClientWindowFrames tmpFrames = new ClientWindowFrames();
- final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0];
+ final InsetsSourceControl[] tmpControls = new InsetsSourceControl[0];
final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
final TaskDescription taskDescription;
@@ -225,13 +226,14 @@
delayRemovalTime, topWindowInsetsState, clearWindowHandler, splashScreenExecutor);
final Window window = snapshotSurface.mWindow;
- final InsetsState mTmpInsetsState = new InsetsState();
+ final InsetsState tmpInsetsState = new InsetsState();
+ final InsetsVisibilities tmpRequestedVisibilities = new InsetsVisibilities();
final InputChannel tmpInputChannel = new InputChannel();
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "TaskSnapshot#addToDisplay");
final int res = session.addToDisplay(window, layoutParams, View.GONE, displayId,
- mTmpInsetsState, tmpInputChannel, mTmpInsetsState, mTempControls);
+ tmpRequestedVisibilities, tmpInputChannel, tmpInsetsState, tmpControls);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (res < 0) {
Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
@@ -244,8 +246,8 @@
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "TaskSnapshot#relayout");
session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0, -1,
- tmpFrames, tmpMergedConfiguration, surfaceControl, mTmpInsetsState,
- mTempControls, TMP_SURFACE_SIZE);
+ tmpFrames, tmpMergedConfiguration, surfaceControl, tmpInsetsState,
+ tmpControls, TMP_SURFACE_SIZE);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
} catch (RemoteException e) {
snapshotSurface.clearWindowSynced();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 7f42fe9..01134a7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -59,6 +59,7 @@
import android.view.Choreographer;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
+import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Transformation;
@@ -132,6 +133,15 @@
@NonNull Transitions.TransitionFinishCallback finishCallback) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
"start default transition animation, info = %s", info);
+
+ // Fallback for screen wake. This just immediately finishes since there is no
+ // animation for screen-wake.
+ if (info.getType() == WindowManager.TRANSIT_WAKE) {
+ startTransaction.apply();
+ finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+ return true;
+ }
+
if (mAnimations.containsKey(transition)) {
throw new IllegalStateException("Got a duplicate startAnimation call for "
+ transition);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
index f432049..bda884c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
@@ -107,6 +107,7 @@
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Checking filter %s",
mFilters.get(i));
if (mFilters.get(i).first.matches(info)) {
+ Slog.d(TAG, "Found filter" + mFilters.get(i));
pendingRemote = mFilters.get(i).second;
// Add to requested list so that it can be found for merge requests.
mRequestedRemotes.put(transition, pendingRemote);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index ba73d55..1a70f76 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -25,6 +25,7 @@
import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_FULLSCREEN;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
@@ -210,15 +211,15 @@
}
@Test
- public void testDragAppOverFullscreenApp_expectSplitScreenAndFullscreenTargets() {
+ public void testDragAppOverFullscreenApp_expectSplitScreenTargets() {
setRunningTask(mFullscreenAppTask);
mPolicy.start(mLandscapeDisplayLayout, mActivityClipData);
ArrayList<Target> targets = assertExactTargetTypes(
- mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
+ mPolicy.getTargets(mInsets), TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_LEFT), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
+ eq(STAGE_TYPE_SIDE), eq(SPLIT_POSITION_TOP_OR_LEFT), any());
reset(mSplitScreenStarter);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
@@ -227,15 +228,15 @@
}
@Test
- public void testDragAppOverFullscreenAppPhone_expectVerticalSplitScreenAndFullscreenTargets() {
+ public void testDragAppOverFullscreenAppPhone_expectVerticalSplitScreenTargets() {
setRunningTask(mFullscreenAppTask);
mPolicy.start(mPortraitDisplayLayout, mActivityClipData);
ArrayList<Target> targets = assertExactTargetTypes(
- mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
+ mPolicy.getTargets(mInsets), TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_TOP), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
+ eq(STAGE_TYPE_SIDE), eq(SPLIT_POSITION_TOP_OR_LEFT), any());
reset(mSplitScreenStarter);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
@@ -244,65 +245,55 @@
}
@Test
- public void testDragAppOverFullscreenNonResizeableApp_expectOnlyFullscreenTargets() {
- setRunningTask(mNonResizeableFullscreenAppTask);
- mPolicy.start(mLandscapeDisplayLayout, mActivityClipData);
- ArrayList<Target> targets = assertExactTargetTypes(
- mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
-
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
- }
-
- @Test
- public void testDragNonResizeableAppOverFullscreenApp_expectOnlyFullscreenTargets() {
- setRunningTask(mFullscreenAppTask);
- mPolicy.start(mLandscapeDisplayLayout, mNonResizeableActivityClipData);
- ArrayList<Target> targets = assertExactTargetTypes(
- mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
-
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
- }
-
- @Test
- public void testDragAppOverSplitApp_expectFullscreenAndSplitTargets() {
+ public void testDragAppOverSplitApp_expectSplitTargets_DropLeft() {
setInSplitScreen(true);
setRunningTask(mSplitPrimaryAppTask);
mPolicy.start(mLandscapeDisplayLayout, mActivityClipData);
ArrayList<Target> targets = assertExactTargetTypes(
- mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
+ mPolicy.getTargets(mInsets), TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_LEFT), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
- reset(mSplitScreenStarter);
+ eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_TOP_OR_LEFT), any());
+ }
- // TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
+ @Test
+ public void testDragAppOverSplitApp_expectSplitTargets_DropRight() {
+ setInSplitScreen(true);
+ setRunningTask(mSplitPrimaryAppTask);
+ mPolicy.start(mLandscapeDisplayLayout, mActivityClipData);
+ ArrayList<Target> targets = assertExactTargetTypes(
+ mPolicy.getTargets(mInsets), TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
+
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_SIDE), eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any());
+ eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any());
}
@Test
- public void testDragAppOverSplitAppPhone_expectFullscreenAndVerticalSplitTargets() {
+ public void testDragAppOverSplitAppPhone_expectVerticalSplitTargets_DropTop() {
setInSplitScreen(true);
setRunningTask(mSplitPrimaryAppTask);
mPolicy.start(mPortraitDisplayLayout, mActivityClipData);
ArrayList<Target> targets = assertExactTargetTypes(
- mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
+ mPolicy.getTargets(mInsets), TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_TOP), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
- reset(mSplitScreenStarter);
+ eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_TOP_OR_LEFT), any());
+ }
- // TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
+ @Test
+ public void testDragAppOverSplitAppPhone_expectVerticalSplitTargets_DropBottom() {
+ setInSplitScreen(true);
+ setRunningTask(mSplitPrimaryAppTask);
+ mPolicy.start(mPortraitDisplayLayout, mActivityClipData);
+ ArrayList<Target> targets = assertExactTargetTypes(
+ mPolicy.getTargets(mInsets), TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
+
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_SIDE), eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any());
+ eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any());
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index 284f384..d536adb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -214,6 +214,7 @@
final ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
taskInfo.topActivityInfo = info;
taskInfo.taskId = taskId;
+ windowInfo.targetActivityInfo = info;
windowInfo.taskInfo = taskInfo;
return windowInfo;
}
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index c4cdb7d..54367b8 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -44,8 +44,6 @@
#include <utils/StrongPointer.h>
#include <utils/Timers.h>
-#include <pthread.h>
-
#include <algorithm>
#include <atomic>
#include <vector>
@@ -60,10 +58,6 @@
struct {
jclass clazz;
jmethodID invokePictureCapturedCallback;
- jmethodID createHintSession;
- jmethodID updateTargetWorkDuration;
- jmethodID reportActualWorkDuration;
- jmethodID closeHintSession;
} gHardwareRenderer;
struct {
@@ -90,14 +84,6 @@
return env;
}
-static bool hasExceptionAndClear(JNIEnv* env) {
- if (GraphicsJNI::hasException(env)) {
- env->ExceptionClear();
- return true;
- }
- return false;
-}
-
typedef ANativeWindow* (*ANW_fromSurface)(JNIEnv* env, jobject surface);
ANW_fromSurface fromSurface;
@@ -147,67 +133,6 @@
}
};
-class HintSessionWrapper : public LightRefBase<HintSessionWrapper> {
-public:
- static sp<HintSessionWrapper> create(JNIEnv* env, RenderProxy* proxy) {
- if (!Properties::useHintManager) return nullptr;
-
- // Include UI thread (self), render thread, and thread pool.
- std::vector<int> tids = CommonPool::getThreadIds();
- tids.push_back(proxy->getRenderThreadTid());
- tids.push_back(pthread_gettid_np(pthread_self()));
-
- jintArray tidsArray = env->NewIntArray(tids.size());
- if (hasExceptionAndClear(env)) return nullptr;
- env->SetIntArrayRegion(tidsArray, 0, tids.size(), reinterpret_cast<jint*>(tids.data()));
- if (hasExceptionAndClear(env)) return nullptr;
- jobject session = env->CallStaticObjectMethod(
- gHardwareRenderer.clazz, gHardwareRenderer.createHintSession, tidsArray);
- if (hasExceptionAndClear(env) || !session) return nullptr;
- return new HintSessionWrapper(env, session);
- }
-
- ~HintSessionWrapper() {
- if (!mSession) return;
- JNIEnv* env = getenv(mVm);
- env->CallStaticVoidMethod(gHardwareRenderer.clazz, gHardwareRenderer.closeHintSession,
- mSession);
- hasExceptionAndClear(env);
- env->DeleteGlobalRef(mSession);
- mSession = nullptr;
- }
-
- void updateTargetWorkDuration(long targetDurationNanos) {
- if (!mSession) return;
- JNIEnv* env = getenv(mVm);
- env->CallStaticVoidMethod(gHardwareRenderer.clazz,
- gHardwareRenderer.updateTargetWorkDuration, mSession,
- static_cast<jlong>(targetDurationNanos));
- hasExceptionAndClear(env);
- }
-
- void reportActualWorkDuration(long actualDurationNanos) {
- if (!mSession) return;
- JNIEnv* env = getenv(mVm);
- env->CallStaticVoidMethod(gHardwareRenderer.clazz,
- gHardwareRenderer.reportActualWorkDuration, mSession,
- static_cast<jlong>(actualDurationNanos));
- hasExceptionAndClear(env);
- }
-
-private:
- HintSessionWrapper(JNIEnv* env, jobject jobject) {
- env->GetJavaVM(&mVm);
- if (jobject) {
- mSession = env->NewGlobalRef(jobject);
- LOG_ALWAYS_FATAL_IF(!mSession, "Failed to make global ref");
- }
- }
-
- JavaVM* mVm = nullptr;
- jobject mSession = nullptr;
-};
-
static void android_view_ThreadedRenderer_rotateProcessStatsBuffer(JNIEnv* env, jobject clazz) {
RenderProxy::rotateProcessStatsBuffer();
}
@@ -235,12 +160,6 @@
RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootRenderNodePtr);
ContextFactoryImpl factory(rootRenderNode);
RenderProxy* proxy = new RenderProxy(translucent, rootRenderNode, &factory);
- sp<HintSessionWrapper> wrapper = HintSessionWrapper::create(env, proxy);
- if (wrapper) {
- proxy->setHintSessionCallbacks(
- [wrapper](int64_t nanos) { wrapper->updateTargetWorkDuration(nanos); },
- [wrapper](int64_t nanos) { wrapper->reportActualWorkDuration(nanos); });
- }
return (jlong) proxy;
}
@@ -1059,18 +978,6 @@
gHardwareRenderer.invokePictureCapturedCallback = GetStaticMethodIDOrDie(env, hardwareRenderer,
"invokePictureCapturedCallback",
"(JLandroid/graphics/HardwareRenderer$PictureCapturedCallback;)V");
- gHardwareRenderer.createHintSession =
- GetStaticMethodIDOrDie(env, hardwareRenderer, "createHintSession",
- "([I)Landroid/os/PerformanceHintManager$Session;");
- gHardwareRenderer.updateTargetWorkDuration =
- GetStaticMethodIDOrDie(env, hardwareRenderer, "updateTargetWorkDuration",
- "(Landroid/os/PerformanceHintManager$Session;J)V");
- gHardwareRenderer.reportActualWorkDuration =
- GetStaticMethodIDOrDie(env, hardwareRenderer, "reportActualWorkDuration",
- "(Landroid/os/PerformanceHintManager$Session;J)V");
- gHardwareRenderer.closeHintSession =
- GetStaticMethodIDOrDie(env, hardwareRenderer, "closeHintSession",
- "(Landroid/os/PerformanceHintManager$Session;)V");
jclass aSurfaceTransactionCallbackClass =
FindClassOrDie(env, "android/graphics/HardwareRenderer$ASurfaceTransactionCallback");
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index db29e34..e7081df 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -16,6 +16,7 @@
#include "DrawFrameTask.h"
+#include <dlfcn.h>
#include <gui/TraceUtils.h>
#include <utils/Log.h>
#include <algorithm>
@@ -26,11 +27,63 @@
#include "../RenderNode.h"
#include "CanvasContext.h"
#include "RenderThread.h"
+#include "thread/CommonPool.h"
namespace android {
namespace uirenderer {
namespace renderthread {
+namespace {
+
+typedef APerformanceHintManager* (*APH_getManager)();
+typedef APerformanceHintSession* (*APH_createSession)(APerformanceHintManager*, const int32_t*,
+ size_t, int64_t);
+typedef void (*APH_updateTargetWorkDuration)(APerformanceHintSession*, int64_t);
+typedef void (*APH_reportActualWorkDuration)(APerformanceHintSession*, int64_t);
+typedef void (*APH_closeSession)(APerformanceHintSession* session);
+
+bool gAPerformanceHintBindingInitialized = false;
+APH_getManager gAPH_getManagerFn = nullptr;
+APH_createSession gAPH_createSessionFn = nullptr;
+APH_updateTargetWorkDuration gAPH_updateTargetWorkDurationFn = nullptr;
+APH_reportActualWorkDuration gAPH_reportActualWorkDurationFn = nullptr;
+APH_closeSession gAPH_closeSessionFn = nullptr;
+
+void ensureAPerformanceHintBindingInitialized() {
+ if (gAPerformanceHintBindingInitialized) return;
+
+ void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
+ LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!");
+
+ gAPH_getManagerFn = (APH_getManager)dlsym(handle_, "APerformanceHint_getManager");
+ LOG_ALWAYS_FATAL_IF(gAPH_getManagerFn == nullptr,
+ "Failed to find required symbol APerformanceHint_getManager!");
+
+ gAPH_createSessionFn = (APH_createSession)dlsym(handle_, "APerformanceHint_createSession");
+ LOG_ALWAYS_FATAL_IF(gAPH_createSessionFn == nullptr,
+ "Failed to find required symbol APerformanceHint_createSession!");
+
+ gAPH_updateTargetWorkDurationFn = (APH_updateTargetWorkDuration)dlsym(
+ handle_, "APerformanceHint_updateTargetWorkDuration");
+ LOG_ALWAYS_FATAL_IF(
+ gAPH_updateTargetWorkDurationFn == nullptr,
+ "Failed to find required symbol APerformanceHint_updateTargetWorkDuration!");
+
+ gAPH_reportActualWorkDurationFn = (APH_reportActualWorkDuration)dlsym(
+ handle_, "APerformanceHint_reportActualWorkDuration");
+ LOG_ALWAYS_FATAL_IF(
+ gAPH_reportActualWorkDurationFn == nullptr,
+ "Failed to find required symbol APerformanceHint_reportActualWorkDuration!");
+
+ gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSession");
+ LOG_ALWAYS_FATAL_IF(gAPH_closeSessionFn == nullptr,
+ "Failed to find required symbol APerformanceHint_closeSession!");
+
+ gAPerformanceHintBindingInitialized = true;
+}
+
+} // namespace
+
DrawFrameTask::DrawFrameTask()
: mRenderThread(nullptr)
, mContext(nullptr)
@@ -39,17 +92,13 @@
DrawFrameTask::~DrawFrameTask() {}
-void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context,
- RenderNode* targetNode) {
+void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode,
+ int32_t uiThreadId, int32_t renderThreadId) {
mRenderThread = thread;
mContext = context;
mTargetNode = targetNode;
-}
-
-void DrawFrameTask::setHintSessionCallbacks(std::function<void(int64_t)> updateTargetWorkDuration,
- std::function<void(int64_t)> reportActualWorkDuration) {
- mUpdateTargetWorkDuration = std::move(updateTargetWorkDuration);
- mReportActualWorkDuration = std::move(reportActualWorkDuration);
+ mUiThreadId = uiThreadId;
+ mRenderThreadId = renderThreadId;
}
void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) {
@@ -144,27 +193,25 @@
unblockUiThread();
}
- // These member callbacks are effectively const as they are set once during init, so it's safe
- // to use these directly instead of making local copies.
- if (mUpdateTargetWorkDuration && mReportActualWorkDuration) {
- constexpr int64_t kSanityCheckLowerBound = 100000; // 0.1ms
- constexpr int64_t kSanityCheckUpperBound = 10000000000; // 10s
- int64_t targetWorkDuration = frameDeadline - intendedVsync;
- targetWorkDuration = targetWorkDuration * Properties::targetCpuTimePercentage / 100;
- if (targetWorkDuration > kSanityCheckLowerBound &&
- targetWorkDuration < kSanityCheckUpperBound &&
- targetWorkDuration != mLastTargetWorkDuration) {
- mLastTargetWorkDuration = targetWorkDuration;
- mUpdateTargetWorkDuration(targetWorkDuration);
- }
- int64_t frameDuration = systemTime(SYSTEM_TIME_MONOTONIC) - frameStartTime;
- int64_t actualDuration = frameDuration -
- (std::min(syncDelayDuration, mLastDequeueBufferDuration)) -
- dequeueBufferDuration;
- if (actualDuration > kSanityCheckLowerBound && actualDuration < kSanityCheckUpperBound) {
- mReportActualWorkDuration(actualDuration);
- }
+ if (!mHintSessionWrapper) mHintSessionWrapper.emplace(mUiThreadId, mRenderThreadId);
+ constexpr int64_t kSanityCheckLowerBound = 100000; // 0.1ms
+ constexpr int64_t kSanityCheckUpperBound = 10000000000; // 10s
+ int64_t targetWorkDuration = frameDeadline - intendedVsync;
+ targetWorkDuration = targetWorkDuration * Properties::targetCpuTimePercentage / 100;
+ if (targetWorkDuration > kSanityCheckLowerBound &&
+ targetWorkDuration < kSanityCheckUpperBound &&
+ targetWorkDuration != mLastTargetWorkDuration) {
+ mLastTargetWorkDuration = targetWorkDuration;
+ mHintSessionWrapper->updateTargetWorkDuration(targetWorkDuration);
}
+ int64_t frameDuration = systemTime(SYSTEM_TIME_MONOTONIC) - frameStartTime;
+ int64_t actualDuration = frameDuration -
+ (std::min(syncDelayDuration, mLastDequeueBufferDuration)) -
+ dequeueBufferDuration;
+ if (actualDuration > kSanityCheckLowerBound && actualDuration < kSanityCheckUpperBound) {
+ mHintSessionWrapper->reportActualWorkDuration(actualDuration);
+ }
+
mLastDequeueBufferDuration = dequeueBufferDuration;
}
@@ -216,6 +263,44 @@
mSignal.signal();
}
+DrawFrameTask::HintSessionWrapper::HintSessionWrapper(int32_t uiThreadId, int32_t renderThreadId) {
+ if (!Properties::useHintManager) return;
+ if (uiThreadId < 0 || renderThreadId < 0) return;
+
+ ensureAPerformanceHintBindingInitialized();
+
+ APerformanceHintManager* manager = gAPH_getManagerFn();
+ if (!manager) return;
+
+ std::vector<int32_t> tids = CommonPool::getThreadIds();
+ tids.push_back(uiThreadId);
+ tids.push_back(renderThreadId);
+
+ // DrawFrameTask code will always set a target duration before reporting actual durations.
+ // So this is just a placeholder value that's never used.
+ int64_t dummyTargetDurationNanos = 16666667;
+ mHintSession =
+ gAPH_createSessionFn(manager, tids.data(), tids.size(), dummyTargetDurationNanos);
+}
+
+DrawFrameTask::HintSessionWrapper::~HintSessionWrapper() {
+ if (mHintSession) {
+ gAPH_closeSessionFn(mHintSession);
+ }
+}
+
+void DrawFrameTask::HintSessionWrapper::updateTargetWorkDuration(long targetDurationNanos) {
+ if (mHintSession) {
+ gAPH_updateTargetWorkDurationFn(mHintSession, targetDurationNanos);
+ }
+}
+
+void DrawFrameTask::HintSessionWrapper::reportActualWorkDuration(long actualDurationNanos) {
+ if (mHintSession) {
+ gAPH_reportActualWorkDurationFn(mHintSession, actualDurationNanos);
+ }
+}
+
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index 2455ea8..6a61a2b 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -16,8 +16,10 @@
#ifndef DRAWFRAMETASK_H
#define DRAWFRAMETASK_H
+#include <optional>
#include <vector>
+#include <performance_hint_private.h>
#include <utils/Condition.h>
#include <utils/Mutex.h>
#include <utils/StrongPointer.h>
@@ -60,9 +62,8 @@
DrawFrameTask();
virtual ~DrawFrameTask();
- void setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode);
- void setHintSessionCallbacks(std::function<void(int64_t)> updateTargetWorkDuration,
- std::function<void(int64_t)> reportActualWorkDuration);
+ void setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode,
+ int32_t uiThreadId, int32_t renderThreadId);
void setContentDrawBounds(int left, int top, int right, int bottom) {
mContentDrawBounds.set(left, top, right, bottom);
}
@@ -85,6 +86,18 @@
}
private:
+ class HintSessionWrapper {
+ public:
+ HintSessionWrapper(int32_t uiThreadId, int32_t renderThreadId);
+ ~HintSessionWrapper();
+
+ void updateTargetWorkDuration(long targetDurationNanos);
+ void reportActualWorkDuration(long actualDurationNanos);
+
+ private:
+ APerformanceHintSession* mHintSession = nullptr;
+ };
+
void postAndWait();
bool syncFrameState(TreeInfo& info);
void unblockUiThread();
@@ -95,6 +108,8 @@
RenderThread* mRenderThread;
CanvasContext* mContext;
RenderNode* mTargetNode = nullptr;
+ int32_t mUiThreadId = -1;
+ int32_t mRenderThreadId = -1;
Rect mContentDrawBounds;
/*********************************************
@@ -112,8 +127,7 @@
nsecs_t mLastDequeueBufferDuration = 0;
nsecs_t mLastTargetWorkDuration = 0;
- std::function<void(int64_t)> mUpdateTargetWorkDuration;
- std::function<void(int64_t)> mReportActualWorkDuration;
+ std::optional<HintSessionWrapper> mHintSessionWrapper;
};
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index a77b5b5..c485ce2 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -29,6 +29,8 @@
#include "utils/Macros.h"
#include "utils/TimeUtils.h"
+#include <pthread.h>
+
namespace android {
namespace uirenderer {
namespace renderthread {
@@ -39,7 +41,8 @@
mContext = mRenderThread.queue().runSync([&]() -> CanvasContext* {
return CanvasContext::create(mRenderThread, translucent, rootRenderNode, contextFactory);
});
- mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode);
+ mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode,
+ pthread_gettid_np(pthread_self()), getRenderThreadTid());
}
RenderProxy::~RenderProxy() {
@@ -48,7 +51,7 @@
void RenderProxy::destroyContext() {
if (mContext) {
- mDrawFrameTask.setContext(nullptr, nullptr, nullptr);
+ mDrawFrameTask.setContext(nullptr, nullptr, nullptr, -1, -1);
// This is also a fence as we need to be certain that there are no
// outstanding mDrawFrame tasks posted before it is destroyed
mRenderThread.queue().runSync([this]() { delete mContext; });
@@ -76,12 +79,6 @@
mRenderThread.queue().runSync([this, name]() { mContext->setName(std::string(name)); });
}
-void RenderProxy::setHintSessionCallbacks(std::function<void(int64_t)> updateTargetWorkDuration,
- std::function<void(int64_t)> reportActualWorkDuration) {
- mDrawFrameTask.setHintSessionCallbacks(std::move(updateTargetWorkDuration),
- std::move(reportActualWorkDuration));
-}
-
void RenderProxy::setSurface(ANativeWindow* window, bool enableTimeout) {
if (window) { ANativeWindow_acquire(window); }
mRenderThread.queue().post([this, win = window, enableTimeout]() mutable {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 1b0f22e..2b5405c 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -71,8 +71,6 @@
void setSwapBehavior(SwapBehavior swapBehavior);
bool loadSystemProperties();
void setName(const char* name);
- void setHintSessionCallbacks(std::function<void(int64_t)> updateTargetWorkDuration,
- std::function<void(int64_t)> reportActualWorkDuration);
void setSurface(ANativeWindow* window, bool enableTimeout = true);
void setSurfaceControl(ASurfaceControl* surfaceControl);
diff --git a/media/java/android/media/metrics/PlaybackErrorEvent.java b/media/java/android/media/metrics/PlaybackErrorEvent.java
index 184b359..4e3b426 100644
--- a/media/java/android/media/metrics/PlaybackErrorEvent.java
+++ b/media/java/android/media/metrics/PlaybackErrorEvent.java
@@ -317,7 +317,7 @@
*/
public static final class Builder {
private @Nullable Exception mException;
- private int mErrorCode;
+ private int mErrorCode = ERROR_UNKNOWN;
private int mSubErrorCode;
private long mTimeSinceCreatedMillis = -1;
private Bundle mMetricsBundle = new Bundle();
diff --git a/media/java/android/media/metrics/PlaybackMetrics.java b/media/java/android/media/metrics/PlaybackMetrics.java
index bbcc484..e71ee20 100644
--- a/media/java/android/media/metrics/PlaybackMetrics.java
+++ b/media/java/android/media/metrics/PlaybackMetrics.java
@@ -502,9 +502,9 @@
private long mMediaDurationMillis = -1;
private int mStreamSource = STREAM_SOURCE_UNKNOWN;
private int mStreamType = STREAM_TYPE_UNKNOWN;
- private int mPlaybackType = PLAYBACK_TYPE_OTHER;
+ private int mPlaybackType = PLAYBACK_TYPE_UNKNOWN;
private int mDrmType = DRM_TYPE_NONE;
- private int mContentType = CONTENT_TYPE_OTHER;
+ private int mContentType = CONTENT_TYPE_UNKNOWN;
private @Nullable String mPlayerName;
private @Nullable String mPlayerVersion;
private @NonNull List<Long> mExperimentIds = new ArrayList<>();
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index ac89fecd..8436ba4 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -416,20 +416,14 @@
return -1;
}
- MtpProperty* property = new MtpProperty(MTP_DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO,
- MTP_TYPE_STR, true);
- if (!property) {
- env->ThrowNew(clazz_io_exception, "Failed to obtain property.");
- return -1;
- }
-
- if (property->getDataType() != MTP_TYPE_STR) {
+ MtpProperty property(MTP_DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO, MTP_TYPE_STR, true);
+ if (property.getDataType() != MTP_TYPE_STR) {
env->ThrowNew(clazz_io_exception, "Unexpected property data type.");
return -1;
}
- property->setCurrentValue(propertyStr);
- if (!device->setDevicePropValueStr(property)) {
+ property.setCurrentValue(propertyStr);
+ if (!device->setDevicePropValueStr(&property)) {
env->ThrowNew(clazz_io_exception, "Failed to obtain property value.");
return -1;
}
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 3ee2c18..32b7a07 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -57,6 +57,7 @@
"net.c",
"obb.cpp",
"permission_manager.cpp",
+ "performance_hint.cpp",
"sensor.cpp",
"sharedmem.cpp",
"storage_manager.cpp",
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index de6db1a..f33e118 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -312,6 +312,13 @@
LIBANDROID_PLATFORM {
global:
+ APerformanceHint_getManager;
+ APerformanceHint_createSession;
+ APerformanceHint_getPreferredUpdateRateNanos;
+ APerformanceHint_updateTargetWorkDuration;
+ APerformanceHint_reportActualWorkDuration;
+ APerformanceHint_closeSession;
+ APerformanceHint_setIHintManagerForTesting;
extern "C++" {
ASurfaceControl_registerSurfaceStatsListener*;
ASurfaceControl_unregisterSurfaceStatsListener*;
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
new file mode 100644
index 0000000..95a2da9
--- /dev/null
+++ b/native/android/performance_hint.cpp
@@ -0,0 +1,241 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "perf_hint"
+
+#include <utility>
+#include <vector>
+
+#include <android/os/IHintManager.h>
+#include <android/os/IHintSession.h>
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+#include <binder/IServiceManager.h>
+#include <performance_hint_private.h>
+#include <utils/SystemClock.h>
+
+using namespace android;
+using namespace android::os;
+
+struct APerformanceHintSession;
+
+struct APerformanceHintManager {
+public:
+ static APerformanceHintManager* getInstance();
+ APerformanceHintManager(sp<IHintManager> service, int64_t preferredRateNanos);
+ APerformanceHintManager() = delete;
+ ~APerformanceHintManager() = default;
+
+ APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
+ int64_t initialTargetWorkDurationNanos);
+ int64_t getPreferredRateNanos() const;
+
+private:
+ static APerformanceHintManager* create(sp<IHintManager> iHintManager);
+
+ sp<IHintManager> mHintManager;
+ const int64_t mPreferredRateNanos;
+};
+
+struct APerformanceHintSession {
+public:
+ APerformanceHintSession(sp<IHintSession> session, int64_t preferredRateNanos,
+ int64_t targetDurationNanos);
+ APerformanceHintSession() = delete;
+ ~APerformanceHintSession();
+
+ int updateTargetWorkDuration(int64_t targetDurationNanos);
+ int reportActualWorkDuration(int64_t actualDurationNanos);
+
+private:
+ friend struct APerformanceHintManager;
+
+ sp<IHintSession> mHintSession;
+ // HAL preferred update rate
+ const int64_t mPreferredRateNanos;
+ // Target duration for choosing update rate
+ int64_t mTargetDurationNanos;
+ // Last update timestamp
+ int64_t mLastUpdateTimestamp;
+ // Cached samples
+ std::vector<int64_t> mActualDurationsNanos;
+ std::vector<int64_t> mTimestampsNanos;
+};
+
+static IHintManager* gIHintManagerForTesting = nullptr;
+static APerformanceHintManager* gHintManagerForTesting = nullptr;
+
+// ===================================== APerformanceHintManager implementation
+APerformanceHintManager::APerformanceHintManager(sp<IHintManager> manager,
+ int64_t preferredRateNanos)
+ : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {}
+
+APerformanceHintManager* APerformanceHintManager::getInstance() {
+ if (gHintManagerForTesting) return gHintManagerForTesting;
+ if (gIHintManagerForTesting) {
+ APerformanceHintManager* manager = create(gIHintManagerForTesting);
+ gIHintManagerForTesting = nullptr;
+ return manager;
+ }
+ static APerformanceHintManager* instance = create(nullptr);
+ return instance;
+}
+
+APerformanceHintManager* APerformanceHintManager::create(sp<IHintManager> manager) {
+ if (!manager) {
+ manager = interface_cast<IHintManager>(
+ defaultServiceManager()->checkService(String16("performance_hint")));
+ }
+ if (manager == nullptr) {
+ ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
+ return nullptr;
+ }
+ int64_t preferredRateNanos = -1L;
+ binder::Status ret = manager->getHintSessionPreferredRate(&preferredRateNanos);
+ if (!ret.isOk()) {
+ ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__,
+ ret.exceptionMessage().c_str());
+ return nullptr;
+ }
+ if (preferredRateNanos <= 0) {
+ ALOGE("%s: PerformanceHint invalid preferred rate.", __FUNCTION__);
+ return nullptr;
+ }
+ return new APerformanceHintManager(std::move(manager), preferredRateNanos);
+}
+
+APerformanceHintSession* APerformanceHintManager::createSession(
+ const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos) {
+ sp<IBinder> token = sp<BBinder>::make();
+ std::vector<int32_t> tids(threadIds, threadIds + size);
+ sp<IHintSession> session;
+ binder::Status ret =
+ mHintManager->createHintSession(token, tids, initialTargetWorkDurationNanos, &session);
+ if (!ret.isOk() || !session) {
+ return nullptr;
+ }
+ return new APerformanceHintSession(std::move(session), mPreferredRateNanos,
+ initialTargetWorkDurationNanos);
+}
+
+int64_t APerformanceHintManager::getPreferredRateNanos() const {
+ return mPreferredRateNanos;
+}
+
+// ===================================== APerformanceHintSession implementation
+
+APerformanceHintSession::APerformanceHintSession(sp<IHintSession> session,
+ int64_t preferredRateNanos,
+ int64_t targetDurationNanos)
+ : mHintSession(std::move(session)),
+ mPreferredRateNanos(preferredRateNanos),
+ mTargetDurationNanos(targetDurationNanos),
+ mLastUpdateTimestamp(elapsedRealtimeNano()) {}
+
+APerformanceHintSession::~APerformanceHintSession() {
+ binder::Status ret = mHintSession->close();
+ if (!ret.isOk()) {
+ ALOGE("%s: HintSession close failed: %s", __FUNCTION__, ret.exceptionMessage().c_str());
+ }
+}
+
+int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
+ if (targetDurationNanos <= 0) {
+ ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__);
+ return EINVAL;
+ }
+ binder::Status ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
+ if (!ret.isOk()) {
+ ALOGE("%s: HintSessionn updateTargetWorkDuration failed: %s", __FUNCTION__,
+ ret.exceptionMessage().c_str());
+ return EPIPE;
+ }
+ mTargetDurationNanos = targetDurationNanos;
+ /**
+ * Most of the workload is target_duration dependent, so now clear the cached samples
+ * as they are most likely obsolete.
+ */
+ mActualDurationsNanos.clear();
+ mTimestampsNanos.clear();
+ mLastUpdateTimestamp = elapsedRealtimeNano();
+ return 0;
+}
+
+int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNanos) {
+ if (actualDurationNanos <= 0) {
+ ALOGE("%s: actualDurationNanos must be positive", __FUNCTION__);
+ return EINVAL;
+ }
+ int64_t now = elapsedRealtimeNano();
+ mActualDurationsNanos.push_back(actualDurationNanos);
+ mTimestampsNanos.push_back(now);
+
+ /**
+ * Use current sample to determine the rate limit. We can pick a shorter rate limit
+ * if any sample underperformed, however, it could be the lower level system is slow
+ * to react. So here we explicitly choose the rate limit with the latest sample.
+ */
+ int64_t rateLimit = actualDurationNanos > mTargetDurationNanos ? mPreferredRateNanos
+ : 10 * mPreferredRateNanos;
+ if (now - mLastUpdateTimestamp <= rateLimit) return 0;
+
+ binder::Status ret =
+ mHintSession->reportActualWorkDuration(mActualDurationsNanos, mTimestampsNanos);
+ mActualDurationsNanos.clear();
+ mTimestampsNanos.clear();
+ if (!ret.isOk()) {
+ ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
+ ret.exceptionMessage().c_str());
+ return EPIPE;
+ }
+ mLastUpdateTimestamp = now;
+ return 0;
+}
+
+// ===================================== C API
+APerformanceHintManager* APerformanceHint_getManager() {
+ return APerformanceHintManager::getInstance();
+}
+
+APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager,
+ const int32_t* threadIds, size_t size,
+ int64_t initialTargetWorkDurationNanos) {
+ return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
+}
+
+int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
+ return manager->getPreferredRateNanos();
+}
+
+int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
+ int64_t targetDurationNanos) {
+ return session->updateTargetWorkDuration(targetDurationNanos);
+}
+
+int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
+ int64_t actualDurationNanos) {
+ return session->reportActualWorkDuration(actualDurationNanos);
+}
+
+void APerformanceHint_closeSession(APerformanceHintSession* session) {
+ delete session;
+}
+
+void APerformanceHint_setIHintManagerForTesting(void* iManager) {
+ delete gHintManagerForTesting;
+ gHintManagerForTesting = nullptr;
+ gIHintManagerForTesting = static_cast<IHintManager*>(iManager);
+}
diff --git a/native/android/tests/performance_hint/Android.bp b/native/android/tests/performance_hint/Android.bp
new file mode 100644
index 0000000..fdc1bc6
--- /dev/null
+++ b/native/android/tests/performance_hint/Android.bp
@@ -0,0 +1,65 @@
+// 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+cc_test {
+ name: "PerformanceHintNativeTestCases",
+
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+
+ srcs: ["PerformanceHintNativeTest.cpp"],
+
+ shared_libs: [
+ "libandroid",
+ "liblog",
+ "libbinder",
+ "libpowermanager",
+ "libutils",
+ ],
+
+ static_libs: [
+ "libbase",
+ "libgmock",
+ "libgtest",
+ ],
+ stl: "c++_shared",
+
+ test_suites: [
+ "device-tests",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ header_libs: [
+ "libandroid_headers_private",
+ ],
+}
diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
new file mode 100644
index 0000000..284e9ee
--- /dev/null
+++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "PerformanceHintNativeTest"
+
+#include <android/os/IHintManager.h>
+#include <android/os/IHintSession.h>
+#include <binder/IBinder.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <performance_hint_private.h>
+#include <memory>
+#include <vector>
+
+using android::binder::Status;
+using android::os::IHintManager;
+using android::os::IHintSession;
+
+using namespace android;
+using namespace testing;
+
+class MockIHintManager : public IHintManager {
+public:
+ MOCK_METHOD(Status, createHintSession,
+ (const ::android::sp<::android::IBinder>& token, const ::std::vector<int32_t>& tids,
+ int64_t durationNanos, ::android::sp<::android::os::IHintSession>* _aidl_return),
+ (override));
+ MOCK_METHOD(Status, getHintSessionPreferredRate, (int64_t * _aidl_return), (override));
+ MOCK_METHOD(IBinder*, onAsBinder, (), (override));
+};
+
+class MockIHintSession : public IHintSession {
+public:
+ MOCK_METHOD(Status, updateTargetWorkDuration, (int64_t targetDurationNanos), (override));
+ MOCK_METHOD(Status, reportActualWorkDuration,
+ (const ::std::vector<int64_t>& actualDurationNanos,
+ const ::std::vector<int64_t>& timeStampNanos),
+ (override));
+ MOCK_METHOD(Status, close, (), (override));
+ MOCK_METHOD(IBinder*, onAsBinder, (), (override));
+};
+
+class PerformanceHintTest : public Test {
+public:
+ void SetUp() override {
+ mMockIHintManager = new StrictMock<MockIHintManager>();
+ APerformanceHint_setIHintManagerForTesting(mMockIHintManager);
+ }
+
+ void TearDown() override {
+ mMockIHintManager = nullptr;
+ // Destroys MockIHintManager.
+ APerformanceHint_setIHintManagerForTesting(nullptr);
+ }
+
+ APerformanceHintManager* createManager() {
+ EXPECT_CALL(*mMockIHintManager, getHintSessionPreferredRate(_))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(123L), Return(Status())));
+ return APerformanceHint_getManager();
+ }
+
+ StrictMock<MockIHintManager>* mMockIHintManager = nullptr;
+};
+
+TEST_F(PerformanceHintTest, TestGetPreferredUpdateRateNanos) {
+ APerformanceHintManager* manager = createManager();
+ int64_t preferredUpdateRateNanos = APerformanceHint_getPreferredUpdateRateNanos(manager);
+ EXPECT_EQ(123L, preferredUpdateRateNanos);
+}
+
+TEST_F(PerformanceHintTest, TestSession) {
+ APerformanceHintManager* manager = createManager();
+
+ std::vector<int32_t> tids;
+ tids.push_back(1);
+ tids.push_back(2);
+ int64_t targetDuration = 56789L;
+
+ StrictMock<MockIHintSession>* iSession = new StrictMock<MockIHintSession>();
+ sp<IHintSession> session_sp(iSession);
+
+ EXPECT_CALL(*mMockIHintManager, createHintSession(_, Eq(tids), Eq(targetDuration), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<3>(std::move(session_sp)), Return(Status())));
+
+ APerformanceHintSession* session =
+ APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration);
+ ASSERT_TRUE(session);
+
+ int64_t targetDurationNanos = 10;
+ EXPECT_CALL(*iSession, updateTargetWorkDuration(Eq(targetDurationNanos))).Times(Exactly(1));
+ int result = APerformanceHint_updateTargetWorkDuration(session, targetDurationNanos);
+ EXPECT_EQ(0, result);
+
+ usleep(2); // Sleep for longer than preferredUpdateRateNanos.
+ int64_t actualDurationNanos = 20;
+ std::vector<int64_t> actualDurations;
+ actualDurations.push_back(20);
+ EXPECT_CALL(*iSession, reportActualWorkDuration(Eq(actualDurations), _)).Times(Exactly(1));
+ result = APerformanceHint_reportActualWorkDuration(session, actualDurationNanos);
+ EXPECT_EQ(0, result);
+
+ result = APerformanceHint_updateTargetWorkDuration(session, -1L);
+ EXPECT_EQ(EINVAL, result);
+ result = APerformanceHint_reportActualWorkDuration(session, -1L);
+ EXPECT_EQ(EINVAL, result);
+
+ EXPECT_CALL(*iSession, close()).Times(Exactly(1));
+ APerformanceHint_closeSession(session);
+}
diff --git a/packages/EasterEgg/AndroidManifest.xml b/packages/EasterEgg/AndroidManifest.xml
index 3d62af0..7f258eb 100644
--- a/packages/EasterEgg/AndroidManifest.xml
+++ b/packages/EasterEgg/AndroidManifest.xml
@@ -1,26 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.egg"
- android:versionCode="1"
+ android:versionCode="12"
android:versionName="1.0">
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<!-- used for cat notifications -->
<uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
+
<!-- used to save cat images -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
<!-- controls -->
<uses-permission android:name="android.permission.BIND_CONTROLS" />
<application
android:icon="@drawable/icon"
android:label="@string/app_name">
-
- <activity android:name=".quares.QuaresActivity"
+ <activity
+ android:name=".quares.QuaresActivity"
+ android:exported="true"
android:icon="@drawable/q_icon"
android:label="@string/q_egg_name"
- android:exported="true"
android:theme="@style/QuaresTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -29,9 +31,9 @@
<activity
android:name=".paint.PaintActivity"
android:configChanges="orientation|keyboardHidden|screenSize|uiMode"
+ android:exported="true"
android:icon="@drawable/p_icon"
android:label="@string/p_egg_name"
- android:exported="true"
android:theme="@style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -39,13 +41,15 @@
</activity>
<!-- Android N easter egg bits -->
- <activity android:name=".neko.NekoLand"
- android:theme="@android:style/Theme.Material.NoActionBar"
+ <activity
+ android:name=".neko.NekoLand"
android:exported="true"
- android:label="@string/app_name">
+ android:label="@string/app_name"
+ android:theme="@android:style/Theme.Material.NoActionBar">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
<action android:name="android.intent.action.MAIN" />
+
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
@@ -54,25 +58,24 @@
<service
android:name=".neko.NekoService"
android:enabled="true"
- android:permission="android.permission.BIND_JOB_SERVICE"
- android:exported="true" >
- </service>
-
+ android:exported="true"
+ android:permission="android.permission.BIND_JOB_SERVICE" />
<!-- Used to show over lock screen -->
- <activity android:name=".neko.NekoLockedActivity"
+ <activity
+ android:name=".neko.NekoLockedActivity"
android:excludeFromRecents="true"
android:exported="true"
- android:theme="@android:style/Theme.Material.Light.Dialog.NoActionBar"
- android:showOnLockScreen="true" />
-
+ android:showOnLockScreen="true"
+ android:theme="@android:style/Theme.Material.Light.Dialog.NoActionBar" />
<!-- Used to enable easter egg -->
- <activity android:name=".neko.NekoActivationActivity"
+ <activity
+ android:name=".ComponentActivationActivity"
android:excludeFromRecents="true"
android:exported="true"
- android:theme="@android:style/Theme.NoDisplay"
- >
+ android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
+ <action android:name="android.intent.action.MAIN" />
+
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.android.internal.category.PLATLOGO" />
</intent-filter>
@@ -81,37 +84,65 @@
<!-- The quick settings tile, disabled by default -->
<service
android:name=".neko.NekoTile"
- android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
- android:icon="@drawable/stat_icon"
android:enabled="false"
android:exported="true"
- android:label="@string/default_tile_name">
+ android:icon="@drawable/stat_icon"
+ android:label="@string/default_tile_name"
+ android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>
-
- <service android:name=".neko.NekoControlsService"
- android:permission="android.permission.BIND_CONTROLS"
- android:label="@string/r_egg_name"
- android:icon="@drawable/ic_fullcat_icon"
+ <service
+ android:name=".neko.NekoControlsService"
android:enabled="false"
- android:exported="true">
+ android:exported="true"
+ android:icon="@drawable/ic_fullcat_icon"
+ android:label="@string/r_egg_name"
+ android:permission="android.permission.BIND_CONTROLS">
<intent-filter>
<action android:name="android.service.controls.ControlsProviderService" />
</intent-filter>
- </service>
-
- <!-- FileProvider for sending pictures -->
+ </service> <!-- FileProvider for sending pictures -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.android.egg.fileprovider"
- android:grantUriPermissions="true"
- android:exported="false">
+ android:exported="false"
+ android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
+
+ <!-- Android S easter egg bits -->
+
+ <!-- List of all system theme colors on the device. -->
+ <activity
+ android:name=".widget.PaintChipsActivity"
+ android:theme="@android:style/Theme.Material.Wallpaper.NoTitleBar"
+ android:configChanges="orientation|keyboardHidden|screenSize|uiMode"
+ android:label="@string/s_egg_name"
+ android:enabled="false"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+
+ <!-- Homescreen widget also showing paint chips (may be affected by the exact position in
+ the workspace) -->
+ <receiver
+ android:name=".widget.PaintChipsWidget"
+ android:label="@string/s_egg_name"
+ android:enabled="false">
+ <intent-filter>
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ </intent-filter>
+
+ <meta-data
+ android:name="android.appwidget.provider"
+ android:resource="@xml/paint_chips_widget_info" />
+ </receiver>
</application>
-</manifest>
+</manifest>
\ No newline at end of file
diff --git a/packages/EasterEgg/build.gradle b/packages/EasterEgg/build.gradle
index 20b4698..0565369 100644
--- a/packages/EasterEgg/build.gradle
+++ b/packages/EasterEgg/build.gradle
@@ -7,8 +7,8 @@
}
dependencies {
- classpath 'com.android.tools.build:gradle:4.0.0'
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath 'com.android.tools.build:gradle:7.0.0-alpha08'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.30"
}
}
@@ -62,6 +62,9 @@
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
+ buildFeatures {
+ viewBinding true
+ }
}
@@ -74,6 +77,7 @@
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.6'
implementation "androidx.recyclerview:recyclerview:${ANDROID_X_VERSION}"
implementation "androidx.dynamicanimation:dynamicanimation:${ANDROID_X_VERSION}"
+ implementation 'com.google.android.material:material:1.3.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
diff --git a/packages/EasterEgg/gradle.properties b/packages/EasterEgg/gradle.properties
index e8e6450..0b5a736 100644
--- a/packages/EasterEgg/gradle.properties
+++ b/packages/EasterEgg/gradle.properties
@@ -19,5 +19,5 @@
kotlin.code.style=official
ANDROID_X_VERSION=1+
-COMPILE_SDK=android-30
+COMPILE_SDK=android-S
BUILD_TOOLS_VERSION=28.0.3
diff --git a/packages/EasterEgg/res/drawable/android_s.xml b/packages/EasterEgg/res/drawable/android_s.xml
new file mode 100644
index 0000000..9cecab1
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/android_s.xml
@@ -0,0 +1,23 @@
+<vector android:height="108dp" android:viewportHeight="48"
+ android:viewportWidth="48" android:width="108dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <group>
+ <clip-path android:pathData="M17,14h14v20h-14z"/>
+ <path android:fillColor="#00000000"
+ android:pathData="M18,21C18,21.7956 18.3161,22.5587 18.8787,23.1213C19.4413,23.6839 20.2044,24 21,24H27C27.7956,24 28.5587,24.3161 29.1213,24.8787C29.6839,25.4413 30,26.2044 30,27"
+ android:strokeColor="#ffffff" android:strokeWidth="2"/>
+ <path android:fillColor="#ffffff" android:pathData="M22,21C22.5523,21 23,20.5523 23,20C23,19.4477 22.5523,19 22,19C21.4477,19 21,19.4477 21,20C21,20.5523 21.4477,21 22,21Z"/>
+ <path android:fillColor="#ffffff" android:pathData="M26,21C26.5523,21 27,20.5523 27,20C27,19.4477 26.5523,19 26,19C25.4477,19 25,19.4477 25,20C25,20.5523 25.4477,21 26,21Z"/>
+ <path android:fillColor="#00000000"
+ android:pathData="M19.5,16.5L18,15"
+ android:strokeColor="#ffffff" android:strokeLineCap="round" android:strokeWidth="2"/>
+ <path android:fillColor="#00000000"
+ android:pathData="M28.5,16.5L30,15"
+ android:strokeColor="#ffffff" android:strokeLineCap="round" android:strokeWidth="2"/>
+ <path android:fillColor="#00000000"
+ android:pathData="M29.92,20C29.8637,19.6605 29.7801,19.3261 29.67,19C29.205,17.6561 28.2777,16.5211 27.0536,15.7973C25.8294,15.0735 24.388,14.8081 22.9864,15.0483C21.5847,15.2885 20.314,16.0188 19.4007,17.1088C18.4874,18.1989 17.991,19.5779 18,21"
+ android:strokeColor="#ffffff" android:strokeLineCap="round" android:strokeWidth="2"/>
+ <path android:fillColor="#00000000"
+ android:pathData="M18.08,28C18.1363,28.3395 18.2199,28.6739 18.33,29C18.795,30.3439 19.7223,31.4789 20.9464,32.2027C22.1705,32.9265 23.612,33.1919 25.0136,32.9517C26.4153,32.7115 27.686,31.9812 28.5993,30.8912C29.5126,29.8011 30.009,28.4221 30,27"
+ android:strokeColor="#ffffff" android:strokeLineCap="round" android:strokeWidth="2"/>
+ </group>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/icon.xml b/packages/EasterEgg/res/drawable/icon.xml
index 7f8d4fa..7054962 100644
--- a/packages/EasterEgg/res/drawable/icon.xml
+++ b/packages/EasterEgg/res/drawable/icon.xml
@@ -15,5 +15,5 @@
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/icon_bg"/>
- <foreground android:drawable="@drawable/android_11_dial"/>
+ <foreground android:drawable="@drawable/android_s"/>
</adaptive-icon>
diff --git a/packages/EasterEgg/res/drawable/icon_bg.xml b/packages/EasterEgg/res/drawable/icon_bg.xml
index 31b2a7f..d08e160 100644
--- a/packages/EasterEgg/res/drawable/icon_bg.xml
+++ b/packages/EasterEgg/res/drawable/icon_bg.xml
@@ -14,5 +14,5 @@
limitations under the License.
-->
<color xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="#073042" />
+ android:color="@android:color/system_accent2_500" />
diff --git a/packages/EasterEgg/res/drawable/roundrect.xml b/packages/EasterEgg/res/drawable/roundrect.xml
new file mode 100644
index 0000000..070adad
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/roundrect.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="#FF000000" />
+ <corners
+ android:radius="12dp" />
+</shape>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/layout/paint_chip.xml b/packages/EasterEgg/res/layout/paint_chip.xml
new file mode 100644
index 0000000..d5745b9
--- /dev/null
+++ b/packages/EasterEgg/res/layout/paint_chip.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/chip"
+ android:layout_width="10dp" android:layout_height="10dp"
+ android:layout_gravity="fill" android:layout_columnWeight="1" android:layout_rowWeight="1"
+ android:text="A1-500"
+ android:backgroundTint="@android:color/system_accent1_500"
+ android:background="@drawable/roundrect"
+ android:gravity="center"
+ android:textColor="?android:attr/textColorPrimary"
+ android:fontFamily="?android:attr/textAppearanceLarge"
+ android:layout_margin="2dp"
+ android:singleLine="true"
+ />
\ No newline at end of file
diff --git a/packages/EasterEgg/res/layout/paint_chips_grid.xml b/packages/EasterEgg/res/layout/paint_chips_grid.xml
new file mode 100644
index 0000000..79f7013
--- /dev/null
+++ b/packages/EasterEgg/res/layout/paint_chips_grid.xml
@@ -0,0 +1,25 @@
+<!--
+ 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.
+-->
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/paint_grid"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="0dp"
+ android:orientation="vertical"
+ android:alignmentMode="alignBounds"
+ android:rowOrderPreserved="false"
+ >
+</GridLayout>
diff --git a/packages/EasterEgg/res/layout/paint_chips_widget_preview.xml b/packages/EasterEgg/res/layout/paint_chips_widget_preview.xml
new file mode 100644
index 0000000..9893ec0
--- /dev/null
+++ b/packages/EasterEgg/res/layout/paint_chips_widget_preview.xml
@@ -0,0 +1,79 @@
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="300dp"
+ android:layout_height="50dp"
+ android:alignmentMode="alignBounds"
+ android:columnCount="5"
+ android:padding="0dp"
+ android:rowCount="1"
+ android:rowOrderPreserved="false">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_rowWeight="1"
+ android:layout_columnWeight="1"
+ android:layout_gravity="fill"
+ android:layout_margin="2dp"
+ android:background="@drawable/roundrect"
+ android:backgroundTint="@android:color/system_neutral1_500"
+ android:fontFamily="?android:attr/textAppearanceLarge"
+ android:gravity="center"
+ android:text="N1-500"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_rowWeight="1"
+ android:layout_columnWeight="1"
+ android:layout_gravity="fill"
+ android:layout_margin="2dp"
+ android:background="@drawable/roundrect"
+ android:backgroundTint="@android:color/system_neutral2_500"
+ android:fontFamily="?android:attr/textAppearanceLarge"
+ android:gravity="center"
+ android:text="N2-500"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_rowWeight="1"
+ android:layout_columnWeight="1"
+ android:layout_gravity="fill"
+ android:layout_margin="2dp"
+ android:background="@drawable/roundrect"
+ android:backgroundTint="@android:color/system_accent1_500"
+ android:fontFamily="?android:attr/textAppearanceLarge"
+ android:gravity="center"
+ android:text="A1-500"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_rowWeight="1"
+ android:layout_columnWeight="1"
+ android:layout_gravity="fill"
+ android:layout_margin="2dp"
+ android:background="@drawable/roundrect"
+ android:backgroundTint="@android:color/system_accent2_500"
+ android:fontFamily="?android:attr/textAppearanceLarge"
+ android:gravity="center"
+ android:text="A2-500"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_rowWeight="1"
+ android:layout_columnWeight="1"
+ android:layout_gravity="fill"
+ android:layout_margin="2dp"
+ android:background="@drawable/roundrect"
+ android:backgroundTint="@android:color/system_accent3_500"
+ android:fontFamily="?android:attr/textAppearanceLarge"
+ android:gravity="center"
+ android:text="A3-500"
+ android:textColor="?android:attr/textColorPrimary" />
+</GridLayout>
diff --git a/packages/EasterEgg/res/values-night/themes.xml b/packages/EasterEgg/res/values-night/themes.xml
new file mode 100644
index 0000000..83ec7a5
--- /dev/null
+++ b/packages/EasterEgg/res/values-night/themes.xml
@@ -0,0 +1,7 @@
+<resources>
+
+ <style name="ThemeOverlay.EasterEgg.AppWidgetContainer" parent="">
+ <item name="appWidgetBackgroundColor">@color/light_blue_900</item>
+ <item name="appWidgetTextColor">@color/light_blue_200</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/values/attrs.xml b/packages/EasterEgg/res/values/attrs.xml
new file mode 100644
index 0000000..97531a2
--- /dev/null
+++ b/packages/EasterEgg/res/values/attrs.xml
@@ -0,0 +1,6 @@
+<resources>
+ <declare-styleable name="AppWidgetAttrs">
+ <attr name="appWidgetBackgroundColor" format="color" />
+ <attr name="appWidgetTextColor" format="color" />
+ </declare-styleable>
+</resources>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/values/colors.xml b/packages/EasterEgg/res/values/colors.xml
index 1a5388b..d79e83b 100644
--- a/packages/EasterEgg/res/values/colors.xml
+++ b/packages/EasterEgg/res/values/colors.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
Copyright (C) 2018 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,4 +17,8 @@
<color name="toolbar_bg_color">#FFDDDDDD</color>
<color name="paper_color">#FFFFFFFF</color>
<color name="paint_color">#FF000000</color>
+ <color name="light_blue_50">#FFE1F5FE</color>
+ <color name="light_blue_200">#FF81D4FA</color>
+ <color name="light_blue_600">#FF039BE5</color>
+ <color name="light_blue_900">#FF01579B</color>
</resources>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/values/dimens.xml b/packages/EasterEgg/res/values/dimens.xml
index e9dcebd..0de2c3c 100644
--- a/packages/EasterEgg/res/values/dimens.xml
+++ b/packages/EasterEgg/res/values/dimens.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?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");
@@ -16,4 +15,10 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<dimen name="neko_display_size">64dp</dimen>
+
+ <!--
+Refer to App Widget Documentation for margin information
+http://developer.android.com/guide/topics/appwidgets/index.html#CreatingLayout
+ -->
+ <dimen name="widget_margin">0dp</dimen>
</resources>
diff --git a/packages/EasterEgg/res/values/strings.xml b/packages/EasterEgg/res/values/strings.xml
index 25f9421..743947a 100644
--- a/packages/EasterEgg/res/values/strings.xml
+++ b/packages/EasterEgg/res/values/strings.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <string name="app_name" translatable="false">Android R Easter Egg</string>
+ <string name="app_name" translatable="false">Android S Easter Egg</string>
<!-- name of the Q easter egg, a nonogram-style icon puzzle -->
<string name="q_egg_name" translatable="false">Icon Quiz</string>
@@ -23,4 +23,8 @@
<string name="p_egg_name" translatable="false">PAINT.APK</string>
<string name="r_egg_name" translatable="false">Cat Controls</string>
+
+ <!-- name of the S easter egg, a widget that displays the system color palette
+ in a manner similar to a set of paint samples from a hardware store -->
+ <string name="s_egg_name" translatable="false">Paint Chips</string>
</resources>
diff --git a/packages/EasterEgg/res/values/themes.xml b/packages/EasterEgg/res/values/themes.xml
new file mode 100644
index 0000000..5b16304
--- /dev/null
+++ b/packages/EasterEgg/res/values/themes.xml
@@ -0,0 +1,7 @@
+<resources>
+
+ <style name="ThemeOverlay.EasterEgg.AppWidgetContainer" parent="">
+ <item name="appWidgetBackgroundColor">@color/light_blue_600</item>
+ <item name="appWidgetTextColor">@color/light_blue_50</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/xml/paint_chips_widget_info.xml b/packages/EasterEgg/res/xml/paint_chips_widget_info.xml
new file mode 100644
index 0000000..7780a75
--- /dev/null
+++ b/packages/EasterEgg/res/xml/paint_chips_widget_info.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
+ android:initialLayout="@layout/paint_chip"
+ android:previewLayout="@layout/paint_chips_widget_preview"
+ android:minWidth="50dp"
+ android:minHeight="50dp"
+ android:resizeMode="horizontal|vertical"
+ android:updatePeriodMillis="86400000"
+ android:widgetCategory="home_screen"></appwidget-provider>
\ No newline at end of file
diff --git a/packages/EasterEgg/src/com/android/egg/ComponentActivationActivity.java b/packages/EasterEgg/src/com/android/egg/ComponentActivationActivity.java
new file mode 100644
index 0000000..5820b5a
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/ComponentActivationActivity.java
@@ -0,0 +1,83 @@
+/*
+ * 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.egg;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.provider.Settings;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.android.egg.neko.NekoControlsService;
+import com.android.egg.widget.PaintChipsActivity;
+import com.android.egg.widget.PaintChipsWidget;
+
+/**
+ * Launched from the PlatLogoActivity. Enables everything else in this easter egg.
+ */
+public class ComponentActivationActivity extends Activity {
+ private static final String TAG = "EasterEgg";
+
+ private static final String S_EGG_UNLOCK_SETTING = "egg_mode_s";
+
+ private void toastUp(String s) {
+ Toast toast = Toast.makeText(this, s, Toast.LENGTH_SHORT);
+ toast.show();
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ final PackageManager pm = getPackageManager();
+ final ComponentName[] cns = new ComponentName[] {
+ new ComponentName(this, NekoControlsService.class),
+ new ComponentName(this, PaintChipsActivity.class),
+ new ComponentName(this, PaintChipsWidget.class)
+ };
+ final long unlockValue = Settings.System.getLong(getContentResolver(),
+ S_EGG_UNLOCK_SETTING, 0);
+ for (ComponentName cn : cns) {
+ final boolean componentEnabled = pm.getComponentEnabledSetting(cn)
+ == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+ if (unlockValue == 0) {
+ if (componentEnabled) {
+ Log.v(TAG, "Disabling component: " + cn);
+ pm.setComponentEnabledSetting(cn,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP);
+ //toastUp("\uD83D\uDEAB");
+ } else {
+ Log.v(TAG, "Already disabled: " + cn);
+ }
+ } else {
+ if (!componentEnabled) {
+ Log.v(TAG, "Enabling component: " + cn);
+ pm.setComponentEnabledSetting(cn,
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ PackageManager.DONT_KILL_APP);
+ //toastUp("\uD83D\uDC31");
+ } else {
+ Log.v(TAG, "Already enabled: " + cn);
+ }
+ }
+ }
+
+ finish();
+ }
+}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java b/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java
deleted file mode 100644
index df461c6..0000000
--- a/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.egg.neko;
-
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.pm.PackageManager;
-import android.provider.Settings;
-import android.util.Log;
-import android.widget.Toast;
-
-import com.android.internal.logging.MetricsLogger;
-
-public class NekoActivationActivity extends Activity {
- private static final String R_EGG_UNLOCK_SETTING = "egg_mode_r";
-
- private void toastUp(String s) {
- Toast toast = Toast.makeText(this, s, Toast.LENGTH_SHORT);
- toast.show();
- }
-
- @Override
- public void onStart() {
- super.onStart();
-
- final PackageManager pm = getPackageManager();
- final ComponentName cn = new ComponentName(this, NekoControlsService.class);
- final boolean componentEnabled = pm.getComponentEnabledSetting(cn)
- == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
- if (Settings.System.getLong(getContentResolver(),
- R_EGG_UNLOCK_SETTING, 0) == 0) {
- if (componentEnabled) {
- Log.v("Neko", "Disabling controls.");
- pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
- PackageManager.DONT_KILL_APP);
- MetricsLogger.histogram(this, "egg_neko_enable", 0);
- toastUp("\uD83D\uDEAB");
- } else {
- Log.v("Neko", "Controls already disabled.");
- }
- } else {
- if (!componentEnabled) {
- Log.v("Neko", "Enabling controls.");
- pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
- PackageManager.DONT_KILL_APP);
- MetricsLogger.histogram(this, "egg_neko_enable", 1);
- toastUp("\uD83D\uDC31");
- } else {
- Log.v("Neko", "Controls already enabled.");
- }
- }
- finish();
- }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/widget/PaintChipsActivity.kt b/packages/EasterEgg/src/com/android/egg/widget/PaintChipsActivity.kt
new file mode 100644
index 0000000..8799aec
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/widget/PaintChipsActivity.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.egg.widget
+
+import android.app.Activity
+import android.content.res.Configuration
+import android.os.Bundle
+import android.widget.FrameLayout
+
+/**
+ * Activity to show off the current dynamic system theme in all its glory.
+ */
+class PaintChipsActivity : Activity() {
+ private lateinit var layout: FrameLayout
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ window.navigationBarColor = 0
+ window.statusBarColor = 0
+ actionBar?.hide()
+
+ layout = FrameLayout(this)
+ layout.setPadding(dp2px(8f), dp2px(8f), dp2px(8f), dp2px(8f))
+ rebuildGrid()
+
+ setContentView(layout)
+ }
+
+ fun dp2px(dp: Float): Int {
+ return (dp * resources.displayMetrics.density).toInt()
+ }
+
+ override fun onResume() {
+ super.onResume()
+
+ rebuildGrid()
+ }
+
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ super.onConfigurationChanged(newConfig)
+
+ rebuildGrid()
+ }
+
+ private fun rebuildGrid() {
+ layout.removeAllViews()
+ val grid = buildFullWidget(this, ClickBehavior.SHARE)
+ val asView = grid.apply(this, layout)
+ layout.addView(asView, FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT))
+ }
+}
diff --git a/packages/EasterEgg/src/com/android/egg/widget/PaintChipsWidget.kt b/packages/EasterEgg/src/com/android/egg/widget/PaintChipsWidget.kt
new file mode 100644
index 0000000..c15cabb
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/widget/PaintChipsWidget.kt
@@ -0,0 +1,293 @@
+/*
+ * 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.egg.widget
+
+import android.app.PendingIntent
+import android.appwidget.AppWidgetManager
+import android.appwidget.AppWidgetProvider
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import android.util.SizeF
+import android.widget.RemoteViews
+
+import com.android.egg.R
+
+/**
+ * A homescreen widget to explore the current dynamic system theme.
+ */
+class PaintChipsWidget : AppWidgetProvider() {
+ override fun onUpdate(
+ context: Context,
+ appWidgetManager: AppWidgetManager,
+ appWidgetIds: IntArray
+ ) {
+ for (appWidgetId in appWidgetIds) {
+ updateAppWidget(context, appWidgetManager, appWidgetId)
+ }
+ }
+
+ override fun onAppWidgetOptionsChanged(
+ context: Context,
+ appWidgetManager: AppWidgetManager,
+ appWidgetId: Int,
+ newOptions: Bundle?
+ ) {
+ // Log.v(TAG, "onAppWidgetOptionsChanged: id=${appWidgetId}")
+ updateAppWidget(context, appWidgetManager, appWidgetId)
+ super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions)
+ }
+}
+
+const val TAG = "PaintChips"
+
+val SHADE_NUMBERS = intArrayOf(0, 10, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000)
+
+val COLORS_NEUTRAL1 = intArrayOf(
+ android.R.color.system_neutral1_0,
+ android.R.color.system_neutral1_10,
+ android.R.color.system_neutral1_50,
+ android.R.color.system_neutral1_100,
+ android.R.color.system_neutral1_200,
+ android.R.color.system_neutral1_300,
+ android.R.color.system_neutral1_400,
+ android.R.color.system_neutral1_500,
+ android.R.color.system_neutral1_600,
+ android.R.color.system_neutral1_700,
+ android.R.color.system_neutral1_800,
+ android.R.color.system_neutral1_900,
+ android.R.color.system_neutral1_1000
+)
+
+val COLORS_NEUTRAL2 = intArrayOf(
+ android.R.color.system_neutral2_0,
+ android.R.color.system_neutral2_10,
+ android.R.color.system_neutral2_50,
+ android.R.color.system_neutral2_100,
+ android.R.color.system_neutral2_200,
+ android.R.color.system_neutral2_300,
+ android.R.color.system_neutral2_400,
+ android.R.color.system_neutral2_500,
+ android.R.color.system_neutral2_600,
+ android.R.color.system_neutral2_700,
+ android.R.color.system_neutral2_800,
+ android.R.color.system_neutral2_900,
+ android.R.color.system_neutral2_1000
+)
+
+var COLORS_ACCENT1 = intArrayOf(
+ android.R.color.system_accent1_0,
+ android.R.color.system_accent1_10,
+ android.R.color.system_accent1_50,
+ android.R.color.system_accent1_100,
+ android.R.color.system_accent1_200,
+ android.R.color.system_accent1_300,
+ android.R.color.system_accent1_400,
+ android.R.color.system_accent1_500,
+ android.R.color.system_accent1_600,
+ android.R.color.system_accent1_700,
+ android.R.color.system_accent1_800,
+ android.R.color.system_accent1_900,
+ android.R.color.system_accent1_1000
+)
+
+var COLORS_ACCENT2 = intArrayOf(
+ android.R.color.system_accent2_0,
+ android.R.color.system_accent2_10,
+ android.R.color.system_accent2_50,
+ android.R.color.system_accent2_100,
+ android.R.color.system_accent2_200,
+ android.R.color.system_accent2_300,
+ android.R.color.system_accent2_400,
+ android.R.color.system_accent2_500,
+ android.R.color.system_accent2_600,
+ android.R.color.system_accent2_700,
+ android.R.color.system_accent2_800,
+ android.R.color.system_accent2_900,
+ android.R.color.system_accent2_1000
+)
+
+var COLORS_ACCENT3 = intArrayOf(
+ android.R.color.system_accent3_0,
+ android.R.color.system_accent3_10,
+ android.R.color.system_accent3_50,
+ android.R.color.system_accent3_100,
+ android.R.color.system_accent3_200,
+ android.R.color.system_accent3_300,
+ android.R.color.system_accent3_400,
+ android.R.color.system_accent3_500,
+ android.R.color.system_accent3_600,
+ android.R.color.system_accent3_700,
+ android.R.color.system_accent3_800,
+ android.R.color.system_accent3_900,
+ android.R.color.system_accent3_1000
+)
+
+var COLOR_NAMES = arrayOf(
+ "N1", "N2", "A1", "A2", "A3"
+)
+
+var COLORS = arrayOf(
+ COLORS_NEUTRAL1,
+ COLORS_NEUTRAL2,
+ COLORS_ACCENT1,
+ COLORS_ACCENT2,
+ COLORS_ACCENT3
+)
+
+internal fun updateAppWidget(
+ context: Context,
+ appWidgetManager: AppWidgetManager,
+ appWidgetId: Int
+) {
+ // val opts = appWidgetManager.getAppWidgetOptions(appWidgetId)
+ // Log.v(TAG, "requested sizes=${opts[OPTION_APPWIDGET_SIZES]}")
+
+ val allSizes = mapOf(
+ SizeF(50f, 50f)
+ to buildWidget(context, 1, 1, ClickBehavior.LAUNCH),
+ SizeF(100f, 50f)
+ to buildWidget(context, 1, 2, ClickBehavior.LAUNCH),
+ SizeF(150f, 50f)
+ to buildWidget(context, 1, 3, ClickBehavior.LAUNCH),
+ SizeF(200f, 50f)
+ to buildWidget(context, 1, 4, ClickBehavior.LAUNCH),
+ SizeF(250f, 50f)
+ to buildWidget(context, 1, 5, ClickBehavior.LAUNCH),
+
+ SizeF(50f, 120f)
+ to buildWidget(context, 3, 1, ClickBehavior.LAUNCH),
+ SizeF(100f, 120f)
+ to buildWidget(context, 3, 2, ClickBehavior.LAUNCH),
+ SizeF(150f, 120f)
+ to buildWidget(context, 3, 3, ClickBehavior.LAUNCH),
+ SizeF(200f, 120f)
+ to buildWidget(context, 3, 4, ClickBehavior.LAUNCH),
+ SizeF(250f, 120f)
+ to buildWidget(context, 3, 5, ClickBehavior.LAUNCH),
+
+ SizeF(50f, 250f)
+ to buildWidget(context, 5, 1, ClickBehavior.LAUNCH),
+ SizeF(100f, 250f)
+ to buildWidget(context, 5, 2, ClickBehavior.LAUNCH),
+ SizeF(150f, 250f)
+ to buildWidget(context, 5, 3, ClickBehavior.LAUNCH),
+ SizeF(200f, 250f)
+ to buildWidget(context, 5, 4, ClickBehavior.LAUNCH),
+ SizeF(250f, 250f)
+ to buildWidget(context, 5, 5, ClickBehavior.LAUNCH),
+
+ SizeF(300f, 300f)
+ to buildWidget(context, SHADE_NUMBERS.size, COLORS.size, ClickBehavior.LAUNCH)
+ )
+
+ // Instruct the widget manager to update the widget
+ appWidgetManager.updateAppWidget(appWidgetId, RemoteViews(allSizes))
+}
+
+fun buildFullWidget(context: Context, clickable: ClickBehavior): RemoteViews {
+ return buildWidget(context, SHADE_NUMBERS.size, COLORS.size, clickable)
+}
+
+fun buildWidget(context: Context, numShades: Int, numColors: Int, clickable: ClickBehavior):
+ RemoteViews {
+ val grid = RemoteViews(context.packageName, R.layout.paint_chips_grid)
+
+ // shouldn't be necessary but sometimes the RV instructions get played twice in launcher.
+ grid.removeAllViews(R.id.paint_grid)
+
+ grid.setInt(R.id.paint_grid, "setRowCount", numShades)
+ grid.setInt(R.id.paint_grid, "setColumnCount", numColors)
+
+ Log.v(TAG, "building widget: shade rows=$numShades, color columns=$numColors")
+
+ COLORS.forEachIndexed colorLoop@{ i, colorlist ->
+ when (colorlist) {
+ COLORS_NEUTRAL1 -> if (numColors < 2) return@colorLoop
+ COLORS_NEUTRAL2 -> if (numColors < 4) return@colorLoop
+ COLORS_ACCENT2 -> if (numColors < 3) return@colorLoop
+ COLORS_ACCENT3 -> if (numColors < 5) return@colorLoop
+ else -> {} // always do ACCENT1
+ }
+ colorlist.forEachIndexed shadeLoop@{ j, resId ->
+ when (SHADE_NUMBERS[j]) {
+ 500 -> {}
+ 300, 700 -> if (numShades < 3) return@shadeLoop
+ 100, 900 -> if (numShades < 5) return@shadeLoop
+ else -> if (numShades < SHADE_NUMBERS.size) return@shadeLoop
+ }
+ val cell = RemoteViews(context.packageName, R.layout.paint_chip)
+ cell.setTextViewText(R.id.chip, "${COLOR_NAMES[i]}-${SHADE_NUMBERS[j]}")
+ val textColor = if (SHADE_NUMBERS[j] > 500)
+ colorlist[0]
+ else colorlist[colorlist.size - 1]
+ cell.setTextColor(R.id.chip, context.getColor(textColor))
+ cell.setColorStateList(R.id.chip, "setBackgroundTintList", resId)
+ val text = """
+ ${COLOR_NAMES[i]}-${SHADE_NUMBERS[j]} (@${
+ context.resources.getResourceName(resId) })
+ currently: #${ String.format("%06x", context.getColor(resId) and 0xFFFFFF) }
+ """.trimIndent()
+ when (clickable) {
+ ClickBehavior.SHARE -> cell.setOnClickPendingIntent(
+ R.id.chip,
+ makeTextSharePendingIntent(context, text)
+ )
+ ClickBehavior.LAUNCH -> cell.setOnClickPendingIntent(
+ R.id.chip,
+ makeActivityLaunchPendingIntent(context)
+ )
+ ClickBehavior.NONE -> { }
+ }
+ grid.addView(R.id.paint_grid, cell)
+ }
+ }
+
+ return grid
+}
+
+enum class ClickBehavior {
+ NONE,
+ SHARE,
+ LAUNCH
+}
+
+fun makeTextSharePendingIntent(context: Context, text: String): PendingIntent {
+ val shareIntent: Intent = Intent().apply {
+ action = Intent.ACTION_SEND
+ putExtra(Intent.EXTRA_TEXT, text)
+ type = "text/plain"
+ }
+
+ val chooserIntent = Intent.createChooser(shareIntent, null).apply {
+ identifier = text // incredible quality-of-life improvement, thanks framework team
+ }
+
+ return PendingIntent.getActivity(context, 0, chooserIntent,
+ PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
+}
+
+fun makeActivityLaunchPendingIntent(context: Context): PendingIntent {
+ return PendingIntent.getActivity(context, 0,
+ Intent().apply {
+ component = ComponentName(context, PaintChipsActivity::class.java)
+ action = Intent.ACTION_MAIN
+ },
+ PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
+}
diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
index f04b0e3..266fc78 100644
--- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
@@ -267,26 +267,22 @@
private static void startLottieAnimationWith(LottieAnimationView illustrationView,
Uri imageUri) {
- try {
- final InputStream inputStream =
- getInputStreamFromUri(illustrationView.getContext(), imageUri);
- illustrationView.setAnimation(inputStream, /* cacheKey= */ null);
- illustrationView.setRepeatCount(LottieDrawable.INFINITE);
- illustrationView.playAnimation();
- } catch (IllegalStateException e) {
- Log.w(TAG, "Invalid illustration image uri: " + imageUri, e);
- }
+ final InputStream inputStream =
+ getInputStreamFromUri(illustrationView.getContext(), imageUri);
+ illustrationView.setFailureListener(
+ result -> Log.w(TAG, "Invalid illustration image uri: " + imageUri, result));
+ illustrationView.setAnimation(inputStream, /* cacheKey= */ null);
+ illustrationView.setRepeatCount(LottieDrawable.INFINITE);
+ illustrationView.playAnimation();
}
private static void startLottieAnimationWith(LottieAnimationView illustrationView,
@RawRes int rawRes) {
- try {
- illustrationView.setAnimation(rawRes);
- illustrationView.setRepeatCount(LottieDrawable.INFINITE);
- illustrationView.playAnimation();
- } catch (IllegalStateException e) {
- Log.w(TAG, "Invalid illustration resource id: " + rawRes, e);
- }
+ illustrationView.setFailureListener(
+ result -> Log.w(TAG, "Invalid illustration resource id: " + rawRes, result));
+ illustrationView.setAnimation(rawRes);
+ illustrationView.setRepeatCount(LottieDrawable.INFINITE);
+ illustrationView.playAnimation();
}
private static void resetAnimations(LottieAnimationView illustrationView) {
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 710ca32..08ca17f 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -172,7 +172,7 @@
<string name="tts_engine_security_warning" msgid="3372432853837988146">"Гэты модуль сінтэзу гаворкі можа збіраць увесь тэкст, які будзе прамоўлены, у тым ліку асабістыя дадзеныя, напрыклад паролі і нумары крэдытных карт. Ён адносіцца да модуля <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Уключыць гэты модуль сінтэзу гаворкі?"</string>
<string name="tts_engine_network_required" msgid="8722087649733906851">"Гэта мова патрабуе актыўнага падключэння да сеткі, каб выконваць функцыю прамаўлення тэксту."</string>
<string name="tts_default_sample_string" msgid="6388016028292967973">"Гэта прыклад сінтэзу гаворкі"</string>
- <string name="tts_status_title" msgid="8190784181389278640">"Статус мовы па змаўчанні"</string>
+ <string name="tts_status_title" msgid="8190784181389278640">"Статус стандартнай мовы"</string>
<string name="tts_status_ok" msgid="8583076006537547379">"<xliff:g id="LOCALE">%1$s</xliff:g> цалкам падтрымліваецца"</string>
<string name="tts_status_requires_network" msgid="8327617638884678896">"Для <xliff:g id="LOCALE">%1$s</xliff:g> патрабуецца падлучэнне да сеткі"</string>
<string name="tts_status_not_supported" msgid="2702997696245523743">"<xliff:g id="LOCALE">%1$s</xliff:g> не падтрымліваецца"</string>
@@ -388,7 +388,7 @@
<string name="local_backup_password_toast_validation_failure" msgid="714669442363647122">"Збой пры ўсталёўцы паролю для рэзервовага капіявання"</string>
<string name="loading_injected_setting_summary" msgid="8394446285689070348">"Ідзе загрузка…"</string>
<string-array name="color_mode_names">
- <item msgid="3836559907767149216">"Сочны (па змаўчанні)"</item>
+ <item msgid="3836559907767149216">"Насычаны (стандартна)"</item>
<item msgid="9112200311983078311">"Натуральныя"</item>
<item msgid="6564241960833766170">"Стандартны"</item>
</string-array>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 8052e2a..ac078fd 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -85,7 +85,7 @@
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"મીડિયા ઑડિયો"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"ફોન કૉલ"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"ફાઇલ સ્થાનાંતરણ"</string>
- <string name="bluetooth_profile_hid" msgid="2969922922664315866">"ઇનપુટ ઉપકરણ"</string>
+ <string name="bluetooth_profile_hid" msgid="2969922922664315866">"ઇનપુટ ડિવાઇસ"</string>
<string name="bluetooth_profile_pan" msgid="1006235139308318188">"ઇન્ટરનેટ ઍક્સેસ"</string>
<string name="bluetooth_profile_pbap" msgid="7064307749579335765">"સંપર્ક શેરિંગ"</string>
<string name="bluetooth_profile_pbap_summary" msgid="2955819694801952056">"સંપર્ક શેરિંગ માટે ઉપયોગ કરો"</string>
@@ -102,7 +102,7 @@
<string name="bluetooth_map_profile_summary_connected" msgid="4141725591784669181">"નકશા સાથે કનેક્ટ થયું"</string>
<string name="bluetooth_sap_profile_summary_connected" msgid="1280297388033001037">"SAP થી કનેક્ટ કરેલ"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="3959741824627764954">"ફાઇલ સ્થાનાંતરણ સેવાથી કનેક્ટ થયેલ નથી"</string>
- <string name="bluetooth_hid_profile_summary_connected" msgid="3923653977051684833">"ઇનપુટ ઉપકરણ સાથે કનેક્ટ થયાં"</string>
+ <string name="bluetooth_hid_profile_summary_connected" msgid="3923653977051684833">"ઇનપુટ ડિવાઇસ સાથે કનેક્ટ થયાં"</string>
<string name="bluetooth_pan_user_profile_summary_connected" msgid="380469653827505727">"ઇન્ટરનેટ ઍક્સેસ માટે ઉપકરણથી કનેક્ટેડ છીએ"</string>
<string name="bluetooth_pan_nap_profile_summary_connected" msgid="3744773111299503493">"ઉપકરણ સાથે સ્થાનિક ઇન્ટરનેટ કનેક્શન શેર કરી રહ્યાં છીએ"</string>
<string name="bluetooth_pan_profile_summary_use_for" msgid="7422039765025340313">"ઇન્ટરનેટ ઍક્સેસ માટે ઉપયોગ કરો"</string>
@@ -155,7 +155,7 @@
<string name="running_process_item_user_label" msgid="3988506293099805796">"વપરાશકર્તા: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"કેટલાંક ડિફોલ્ટ્સ સેટ કરેલ છે"</string>
<string name="launch_defaults_none" msgid="8049374306261262709">"કોઈ ડિફૉલ્ટ સેટ કરેલા નથી"</string>
- <string name="tts_settings" msgid="8130616705989351312">"ટેક્સ્ટ-ટુ-સ્પીચ સેટિંગ્સ"</string>
+ <string name="tts_settings" msgid="8130616705989351312">"ટેક્સ્ટ ટૂ સ્પીચ સેટિંગ"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"ટેક્સ્ટ ટુ સ્પીચ આઉટપુટ"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"વાણી દર"</string>
<string name="tts_default_rate_summary" msgid="3781937042151716987">"ટેક્સ્ટ બોલાયેલ છે તે ઝડપ"</string>
@@ -177,8 +177,8 @@
<string name="tts_status_requires_network" msgid="8327617638884678896">"<xliff:g id="LOCALE">%1$s</xliff:g> નેટવર્ક કનેક્શનની આવશ્યકતા છે"</string>
<string name="tts_status_not_supported" msgid="2702997696245523743">"<xliff:g id="LOCALE">%1$s</xliff:g> સમર્થિત નથી"</string>
<string name="tts_status_checking" msgid="8026559918948285013">"તપાસી રહ્યું છે..."</string>
- <string name="tts_engine_settings_title" msgid="7849477533103566291">"<xliff:g id="TTS_ENGINE_NAME">%s</xliff:g> માટેની સેટિંગ્સ"</string>
- <string name="tts_engine_settings_button" msgid="477155276199968948">"એન્જિન સેટિંગ્સ લોંચ કરો"</string>
+ <string name="tts_engine_settings_title" msgid="7849477533103566291">"<xliff:g id="TTS_ENGINE_NAME">%s</xliff:g> માટેના સેટિંગ"</string>
+ <string name="tts_engine_settings_button" msgid="477155276199968948">"એન્જિન સેટિંગ લૉન્ચ કરો"</string>
<string name="tts_engine_preference_section_title" msgid="3861562305498624904">"મનપસંદ એન્જિન"</string>
<string name="tts_general_section_title" msgid="8919671529502364567">"સામાન્ય"</string>
<string name="tts_reset_speech_pitch_title" msgid="7149398585468413246">"સ્પીચની પિચ ફરીથી સેટ કરો"</string>
@@ -201,9 +201,9 @@
<string name="development_settings_enable" msgid="4285094651288242183">"વિકાસકર્તાનાં વિકલ્પો સક્ષમ કરો"</string>
<string name="development_settings_summary" msgid="8718917813868735095">"ઍપ્લિકેશન વિકાસ માટે વિકલ્પો સેટ કરો"</string>
<string name="development_settings_not_available" msgid="355070198089140951">"આ વપરાશકર્તા માટે વિકાસકર્તા વિકલ્પો ઉપલબ્ધ નથી"</string>
- <string name="vpn_settings_not_available" msgid="2894137119965668920">"આ વપરાશકર્તા માટે VPN સેટિંગ્સ ઉપલબ્ધ નથી"</string>
- <string name="tethering_settings_not_available" msgid="266821736434699780">"આ વપરાશકર્તા માટે ટિથરિંગ સેટિંગ્સ ઉપલબ્ધ નથી"</string>
- <string name="apn_settings_not_available" msgid="1147111671403342300">"અૅક્સેસ પોઇન્ટનું નામ સેટિંગ્સ આ વપરાશકર્તા માટે ઉપલબ્ધ નથી"</string>
+ <string name="vpn_settings_not_available" msgid="2894137119965668920">"આ વપરાશકર્તા માટે VPN સેટિંગ ઉપલબ્ધ નથી"</string>
+ <string name="tethering_settings_not_available" msgid="266821736434699780">"આ વપરાશકર્તા માટે ટિથરિંગ સેટિંગ ઉપલબ્ધ નથી"</string>
+ <string name="apn_settings_not_available" msgid="1147111671403342300">"અૅક્સેસ પૉઇન્ટનું નામ સેટિંગ આ વપરાશકર્તા માટે ઉપલબ્ધ નથી"</string>
<string name="enable_adb" msgid="8072776357237289039">"USB ડિબગીંગ"</string>
<string name="enable_adb_summary" msgid="3711526030096574316">"જ્યારે USB કનેક્ટ કરેલું હોય ત્યારે ડિબગ મોડ"</string>
<string name="clear_adb_keys" msgid="3010148733140369917">"USB ડીબગિંગ પ્રમાણીકરણોને રદબાતલ કરો"</string>
@@ -259,7 +259,7 @@
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ચોક્કસ વૉલ્યૂમને બંધ કરો"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche ચાલુ કરો"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"બ્લૂટૂથ AVRCP વર્ઝન"</string>
- <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"બ્લૂટૂથ AVRCP સંસ્કરણ પસંદ કરો"</string>
+ <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"બ્લૂટૂથ AVRCP વર્ઝન પસંદ કરો"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"બ્લૂટૂથ MAP વર્ઝન"</string>
<string name="bluetooth_select_map_version_dialog_title" msgid="7085934373987428460">"બ્લૂટૂથ MAP વર્ઝન પસંદ કરો"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="952001408455456494">"બ્લૂટૂથ ઑડિયો કોડેક"</string>
@@ -301,12 +301,12 @@
<string name="mobile_data_always_on_summary" msgid="1112156365594371019">"વાઇ-ફાઇ સક્રિય હોય ત્યારે પણ, હંમેશા મોબાઇલ ડેટાને સક્રિય રાખો (ઝડપી નેટવર્ક સ્વિચિંગ માટે)."</string>
<string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"જો ટિથરિંગ માટે હાર્ડવેર ગતિવૃદ્ધિ ઉપલબ્ધ હોય તો તેનો ઉપયોગ કરો"</string>
<string name="adb_warning_title" msgid="7708653449506485728">"USB ડિબગિંગને મંજૂરી આપીએ?"</string>
- <string name="adb_warning_message" msgid="8145270656419669221">"USB ડિબગીંગ ફક્ત વિકાસ હેતુઓ માટે જ બનાવાયેલ છે. તેનો ઉપયોગ તમારા કમ્પ્યુટર અને તમારા ઉપકરણ વચ્ચે ડેટાને કૉપિ કરવા, નોટિફિકેશન વગર તમારા ઉપકરણ પર ઍપ્લિકેશનો ઇન્સ્ટોલ કરવા અને લૉગ ડેટા વાંચવા માટે કરો."</string>
+ <string name="adb_warning_message" msgid="8145270656419669221">"USB ડિબગીંગ ફક્ત વિકાસ હેતુઓ માટે જ બનાવાયેલ છે. તેનો ઉપયોગ તમારા કમ્પ્યુટર અને તમારા ડિવાઇસ વચ્ચે ડેટાને કૉપિ કરવા, નોટિફિકેશન વગર તમારા ડિવાઇસ પર ઍપ ઇન્સ્ટોલ કરવા અને લૉગ ડેટા વાંચવા માટે કરો."</string>
<string name="adbwifi_warning_title" msgid="727104571653031865">"વાયરલેસ ડિબગીંગને મંજૂરી આપીએ?"</string>
<string name="adbwifi_warning_message" msgid="8005936574322702388">"વાયરલેસ ડિબગીંગ ફક્ત ડેવલપમેન્ટના હેતુઓ માટે જ બનાવાયું છે. તેનો ઉપયોગ તમારા કમ્પ્યુટર અને તમારા ડિવાઇસ વચ્ચે ડેટાને કૉપિ કરવા, નોટિફિકેશન વગર તમારા ડિવાઇસ પર ઍપને ઇન્સ્ટૉલ કરવા અને લૉગ ડેટા વાંચવા માટે કરો."</string>
<string name="adb_keys_warning_message" msgid="2968555274488101220">"તમે અગાઉ અધિકૃત કરેલા તમામ કમ્પ્યુટર્સમાંથી USB ડિબગિંગ પરની અૅક્સેસ રદબાતલ કરીએ?"</string>
- <string name="dev_settings_warning_title" msgid="8251234890169074553">"વિકાસ સેટિંગ્સને મંજૂરી આપીએ?"</string>
- <string name="dev_settings_warning_message" msgid="37741686486073668">"આ સેટિંગ્સ ફક્ત વિકાસનાં ઉપયોગ માટે જ હેતુબદ્ધ છે. તે તમારા ઉપકરણ અને તેના પરની એપ્લિકેશન્સનાં ભંગ થવા અથવા ખરાબ વર્તનનું કારણ બની શકે છે."</string>
+ <string name="dev_settings_warning_title" msgid="8251234890169074553">"ડેવલપમેન્ટ સેટિંગને મંજૂરી આપીએ?"</string>
+ <string name="dev_settings_warning_message" msgid="37741686486073668">"આ સેટિંગ ફક્ત વિકાસનાં ઉપયોગ માટે જ હેતુબદ્ધ છે. તે તમારા ડિવાઇસ અને તેના પરની ઍપના ભંગ થવા અથવા ખરાબ વર્તનનું કારણ બની શકે છે."</string>
<string name="verify_apps_over_usb_title" msgid="6031809675604442636">"USB પર ઍપ ચકાસો"</string>
<string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"હાનિકારક વર્તણૂંક માટે ADB/ADT મારફતે ઇન્સ્ટોલ કરવામાં આવેલી ઍપ તપાસો."</string>
<string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"નામ વગરના (ફક્ત MAC ઍડ્રેસવાળા) બ્લૂટૂથ ડિવાઇસ બતાવવામાં આવશે"</string>
@@ -468,7 +468,7 @@
<string name="external_source_trusted" msgid="1146522036773132905">"મંજૂરી છે"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"મંજૂરી નથી"</string>
<string name="install_other_apps" msgid="3232595082023199454">"અજાણી ઍપ ઇન્સ્ટૉલ કરો"</string>
- <string name="home" msgid="973834627243661438">"સેટિંગ્સ હોમ"</string>
+ <string name="home" msgid="973834627243661438">"સેટિંગ હોમ"</string>
<string-array name="battery_labels">
<item msgid="7878690469765357158">"0%"</item>
<item msgid="8894873528875953317">"50%"</item>
@@ -488,7 +488,7 @@
<string name="retail_demo_reset_title" msgid="1866911701095959800">"પાસવર્ડ આવશ્યક છે"</string>
<string name="active_input_method_subtypes" msgid="4232680535471633046">"ઇનપુટ પદ્ધતિઓ સક્રિય કરો"</string>
<string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"સિસ્ટમ ભાષાઓનો ઉપયોગ કરો"</string>
- <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> માટેની સેટિંગ્સ ખોલવામાં નિષ્ફળ"</string>
+ <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> માટેના સેટિંગ ખોલવામાં નિષ્ફળ"</string>
<string name="ime_security_warning" msgid="6547562217880551450">"આ ઇનપુટ પદ્ધતિ પાસવર્ડ્સ અને ક્રેડિટ કાર્ડ નંબર જેવી વ્યક્તિગત માહિતી સહિત તમે લખો છો તે તમામ ટેક્સ્ટ એકત્રિત કરવા માટે સક્ષમ હોઈ શકે છે. તે ઍપ્લિકેશન <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> માંથી આવે છે. આ ઇનપુટ પદ્ધતિ વાપરીએ?"</string>
<string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"નોંધ: રીબૂટ કર્યાં પછી, જ્યાં સુધી તમે તમારો ફોન અનલૉક કરશો નહીં ત્યાં સુધી આ ઍપ્લિકેશન શરૂ થઈ શકશે નહીં"</string>
<string name="ims_reg_title" msgid="8197592958123671062">"IMS રજિસ્ટ્રેશનની સ્થિતિ"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 5ac22ff..2576993 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -155,8 +155,8 @@
<string name="running_process_item_user_label" msgid="3988506293099805796">"Хэрэглэгч: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"Зарим үндсэн тохиргоонуудыг суулгасан"</string>
<string name="launch_defaults_none" msgid="8049374306261262709">"Ямар ч үндсэн тохиргоог суулгаагүй байна"</string>
- <string name="tts_settings" msgid="8130616705989351312">"Текст-ярианы тохиргоо"</string>
- <string name="tts_settings_title" msgid="7602210956640483039">"Текстийг яриа болгон гаргах"</string>
+ <string name="tts_settings" msgid="8130616705989351312">"Бичвэрийг ярианд хувиргах тохиргоо"</string>
+ <string name="tts_settings_title" msgid="7602210956640483039">"Бичвэрийг ярианд хувиргах"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"Ярианы түвшин"</string>
<string name="tts_default_rate_summary" msgid="3781937042151716987">"Текстийг унших хурд"</string>
<string name="tts_default_pitch_title" msgid="6988592215554485479">"Авиа тон"</string>
@@ -170,7 +170,7 @@
<string name="tts_install_data_title" msgid="1829942496472751703">"Хоолойн өгөгдлийг суулгах"</string>
<string name="tts_install_data_summary" msgid="3608874324992243851">"Яриа үүсгэхэд шаардлагатай дууны өгөгдлийг суулгах"</string>
<string name="tts_engine_security_warning" msgid="3372432853837988146">"Энэ яриа үүсгүүр нь нууц үг, зээлийн картын дугаар гэх мэт таны хувийн мэдээллийг оруулан унших бүх текстийг цуглуулах боломжтой. Үүнийг <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g> үүсгүүрээс нийлүүлдэг. Энэ яриа үүсгүүрийн ашиглалтыг идэвхжүүлэх үү?"</string>
- <string name="tts_engine_network_required" msgid="8722087649733906851">"Энэ хэл нь текстээс дуунд хөрвүүлэхэд ажлын сүлжээний холболтыг шаарддаг."</string>
+ <string name="tts_engine_network_required" msgid="8722087649733906851">"Энэ хэл нь бичвэрийг ярианд хувиргахад ажлын сүлжээний холболт шаардана."</string>
<string name="tts_default_sample_string" msgid="6388016028292967973">"Энэ бол яриа үүсгэх жишээ юм."</string>
<string name="tts_status_title" msgid="8190784181389278640">"Үндсэн хэлний статус"</string>
<string name="tts_status_ok" msgid="8583076006537547379">"<xliff:g id="LOCALE">%1$s</xliff:g> бүрэн дэмжигдсэн"</string>
diff --git a/packages/SettingsLib/res/values-pl/arrays.xml b/packages/SettingsLib/res/values-pl/arrays.xml
index db621be..22b0539 100644
--- a/packages/SettingsLib/res/values-pl/arrays.xml
+++ b/packages/SettingsLib/res/values-pl/arrays.xml
@@ -247,7 +247,7 @@
<item msgid="5023908510820531131">"W: <xliff:g id="AS_TYPED_COMMAND">adb shell dumpsys gfxinfo</xliff:g>"</item>
</string-array>
<string-array name="debug_hw_overdraw_entries">
- <item msgid="1968128556747588800">"Wył."</item>
+ <item msgid="1968128556747588800">"Wyłączone"</item>
<item msgid="3033215374382962216">"Pokaż przerysowywane obszary"</item>
<item msgid="3474333938380896988">"Pokaż obszary dostosowane do deuteranomalii"</item>
</string-array>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 490d3aa..055760d 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -88,8 +88,8 @@
<string name="bluetooth_profile_hid" msgid="2969922922664315866">"Vnosna naprava"</string>
<string name="bluetooth_profile_pan" msgid="1006235139308318188">"Internetni dostop"</string>
<string name="bluetooth_profile_pbap" msgid="7064307749579335765">"Deljenje stikov"</string>
- <string name="bluetooth_profile_pbap_summary" msgid="2955819694801952056">"Uporabi za dajanje stikov v skupno rabo"</string>
- <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Skupna raba internetne povezave"</string>
+ <string name="bluetooth_profile_pbap_summary" msgid="2955819694801952056">"Uporabi za deljenje stikov"</string>
+ <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Deljenje internetne povezave"</string>
<string name="bluetooth_profile_map" msgid="8907204701162107271">"Sporočila SMS"</string>
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Dostop do kartice SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Zvok visoke kakovosti: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
@@ -104,7 +104,7 @@
<string name="bluetooth_opp_profile_summary_not_connected" msgid="3959741824627764954">"Povezava s strežnikom za prenos datotek ni vzpostavljena"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3923653977051684833">"Povezava z vnosno napravo je vzpostavljena"</string>
<string name="bluetooth_pan_user_profile_summary_connected" msgid="380469653827505727">"Povezava z napravo za internetni dostop"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="3744773111299503493">"Skupna raba lok. internetne povezave z napravo"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="3744773111299503493">"Deljenje lok. internetne povezave z napravo"</string>
<string name="bluetooth_pan_profile_summary_use_for" msgid="7422039765025340313">"Uporabi za dostop do interneta"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="4453622103977592583">"Uporabi za zemljevid"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="6204902866176714046">"Uporablja se za dostop do kartice SIM"</string>
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
index ea9be04..9e3312a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
@@ -18,6 +18,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -130,4 +132,27 @@
verify(drawable).start();
}
+
+ @Test
+ public void playLottieAnimationWithUri_verifyFailureListener() {
+ doReturn(null).when(mAnimationView).getDrawable();
+
+ mPreference.setImageUri(mImageUri);
+ mPreference.onBindViewHolder(mViewHolder);
+
+ verify(mAnimationView).setFailureListener(any());
+ }
+
+ @Test
+ public void playLottieAnimationWithResource_verifyFailureListener() {
+ // fake the valid lottie image
+ final int fakeValidResId = 111;
+ doNothing().when(mAnimationView).setImageResource(fakeValidResId);
+ doReturn(null).when(mAnimationView).getDrawable();
+
+ mPreference.setLottieAnimationResId(fakeValidResId);
+ mPreference.onBindViewHolder(mViewHolder);
+
+ verify(mAnimationView).setFailureListener(any());
+ }
}
diff --git a/packages/SettingsProvider/res/values-gu/strings.xml b/packages/SettingsProvider/res/values-gu/strings.xml
index 1f91f71..dded10e 100644
--- a/packages/SettingsProvider/res/values-gu/strings.xml
+++ b/packages/SettingsProvider/res/values-gu/strings.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4567566098528588863">"સેટિંગ્સ સંગ્રહ"</string>
+ <string name="app_label" msgid="4567566098528588863">"સેટિંગ સ્ટોરેજ"</string>
<string name="wifi_softap_config_change" msgid="5688373762357941645">"હૉટસ્પૉટ સેટિંગ બદલાઈ ગઈ છે"</string>
<string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"વિગતો જોવા માટે ટૅપ કરો"</string>
</resources>
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
index eb81961..01ae1e9 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -76,5 +76,7 @@
Settings.Global.ARE_USER_DISABLED_HDR_FORMATS_ALLOWED,
Settings.Global.DEVICE_CONFIG_SYNC_DISABLED,
Settings.Global.POWER_BUTTON_LONG_PRESS,
+ Settings.Global.AUTOMATIC_POWER_SAVE_MODE,
+ Settings.Global.ADVANCED_BATTERY_USAGE_AMOUNT,
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index 5220a04..3c7d7a8 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -140,6 +140,8 @@
/* last= */Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT));
VALIDATORS.put(Global.DISABLE_WINDOW_BLURS, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.DEVICE_CONFIG_SYNC_DISABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Global.AUTOMATIC_POWER_SAVE_MODE, ANY_INTEGER_VALIDATOR);
+ VALIDATORS.put(Global.ADVANCED_BATTERY_USAGE_AMOUNT, PERCENTAGE_INTEGER_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 6d7fb02..7a9f81e0 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -276,7 +276,7 @@
VALIDATORS.put(Secure.ACCESSIBILITY_BUTTON_MODE,
new InclusiveIntegerRangeValidator(
Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR,
- Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU));
+ Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE));
VALIDATORS.put(Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
new DiscreteValueValidator(new String[] {"0", "1"}));
VALIDATORS.put(Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE,
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 3297937..9362a18 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -137,7 +137,6 @@
Settings.Global.AUTOFILL_LOGGING_LEVEL,
Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE,
Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS,
- Settings.Global.AUTOMATIC_POWER_SAVE_MODE,
Settings.Global.AVERAGE_TIME_TO_DISCHARGE,
Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY,
Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME,
@@ -592,8 +591,7 @@
Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER,
Settings.Global.CACHED_APPS_FREEZER_ENABLED,
Settings.Global.APP_INTEGRITY_VERIFICATION_TIMEOUT,
- Settings.Global.KEY_CHORD_POWER_VOLUME_UP,
- Settings.Global.ADVANCED_BATTERY_USAGE_AMOUNT);
+ Settings.Global.KEY_CHORD_POWER_VOLUME_UP);
private static final Set<String> BACKUP_DENY_LIST_SECURE_SETTINGS =
newHashSet(
diff --git a/packages/Shell/res/values-sl/strings.xml b/packages/Shell/res/values-sl/strings.xml
index 1fc27ca..76702d6 100644
--- a/packages/Shell/res/values-sl/strings.xml
+++ b/packages/Shell/res/values-sl/strings.xml
@@ -24,7 +24,7 @@
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Počakajte ..."</string>
<string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"Poročilo o napakah bo kmalu prikazano v telefonu"</string>
<string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"Izberite za pošiljanje poročila o napakah"</string>
- <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Dotaknite se, če želite poročilo o napaki dati v skupno rabo"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Dotaknite se, če želite deliti poročilo o napaki"</string>
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Izberite za pošiljanje poročila o napakah brez posnetka zaslona ali počakajte, da se ta dokonča"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Dotaknite se za pošiljanje poročila o napakah brez posnetka zaslona ali počakajte, da se ta dokonča"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Dotaknite se za pošiljanje poročila o napakah brez posnetka zaslona ali počakajte, da se ta dokonča"</string>
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index bd2209b..0424382 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -52,13 +52,6 @@
void setListening(boolean listening);
boolean isShowingDetail();
void closeDetail();
-
- /**
- * Set that we're currently pulse expanding
- *
- * @param pulseExpanding if we're currently expanding during pulsing
- */
- default void setPulseExpanding(boolean pulseExpanding) {}
void animateHeaderSlidingOut();
void setQsExpansion(float qsExpansionFraction, float headerTranslation);
void setHeaderListening(boolean listening);
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
index 02cb2bc..a22a56f 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
@@ -20,171 +20,166 @@
<com.android.keyguard.KeyguardPINView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/res-auto"
- android:id="@+id/keyguard_pin_view"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/keyguard_pin_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
androidprv:layout_maxWidth="@dimen/keyguard_security_width"
android:orientation="vertical"
>
- <LinearLayout
- android:id="@+id/pin_container"
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/pin_container"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_marginBottom="8dp"
+ android:layout_weight="1"
+ android:layoutDirection="ltr"
+ android:orientation="vertical">
+
+ <!-- Set this to be just above key1. It would be better to introduce a barrier above
+ key1/key2/key3, then place this View above that. Sadly, that doesn't work (the Barrier
+ drops to the bottom of the page, and key1/2/3 all shoot up to the top-left). In any
+ case, the Flow should ensure that key1/2/3 all have the same top, so this should be
+ fine. -->
+ <com.android.keyguard.AlphaOptimizedRelativeLayout
+ android:id="@+id/row0"
android:layout_width="match_parent"
- android:layout_height="0dp"
- android:orientation="vertical"
- android:layout_weight="1"
- android:layoutDirection="ltr"
- android:layout_marginBottom="8dp"
- >
- <Space
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- />
- <com.android.keyguard.AlphaOptimizedRelativeLayout
- android:id="@+id/row0"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom"
- >
+ android:layout_height="wrap_content"
+ android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom"
+ androidprv:layout_constraintBottom_toTopOf="@id/key1"
+ androidprv:layout_constraintEnd_toEndOf="parent"
+ androidprv:layout_constraintStart_toStartOf="parent"
+
+ androidprv:layout_constraintTop_toTopOf="parent"
+ androidprv:layout_constraintVertical_bias="1.0">
+
<com.android.keyguard.PasswordTextView
- android:id="@+id/pinEntry"
- android:layout_width="@dimen/keyguard_security_width"
- android:layout_height="@dimen/keyguard_password_height"
- style="@style/Widget.TextView.Password"
- android:layout_centerHorizontal="true"
- android:layout_marginRight="72dp"
- androidprv:scaledTextSize="@integer/scaled_password_text_size"
- android:contentDescription="@string/keyguard_accessibility_pin_area"
- />
+ android:id="@+id/pinEntry"
+ style="@style/Widget.TextView.Password"
+ android:layout_width="@dimen/keyguard_security_width"
+ android:layout_height="@dimen/keyguard_password_height"
+ android:layout_centerHorizontal="true"
+ android:layout_marginRight="72dp"
+ android:contentDescription="@string/keyguard_accessibility_pin_area"
+ androidprv:scaledTextSize="@integer/scaled_password_text_size" />
</com.android.keyguard.AlphaOptimizedRelativeLayout>
- <LinearLayout
- android:id="@+id/row1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_gravity="center_horizontal"
- android:layout_marginBottom="@dimen/num_pad_row_margin_bottom"
- >
- <com.android.keyguard.NumPadKey
- android:id="@+id/key1"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/pinEntry"
- androidprv:digit="1"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key2"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/pinEntry"
- androidprv:digit="2"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key3"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- androidprv:textView="@+id/pinEntry"
- androidprv:digit="3"
- />
- </LinearLayout>
- <LinearLayout
- android:id="@+id/row2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_gravity="center_horizontal"
- android:layout_marginBottom="@dimen/num_pad_row_margin_bottom"
- >
- <com.android.keyguard.NumPadKey
- android:id="@+id/key4"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/pinEntry"
- androidprv:digit="4"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key5"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/pinEntry"
- androidprv:digit="5"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key6"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- androidprv:textView="@+id/pinEntry"
- androidprv:digit="6"
- />
- </LinearLayout>
- <LinearLayout
- android:id="@+id/row3"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_gravity="center_horizontal"
- android:layout_marginBottom="@dimen/num_pad_row_margin_bottom"
- >
- <com.android.keyguard.NumPadKey
- android:id="@+id/key7"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/pinEntry"
- androidprv:digit="7"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key8"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/pinEntry"
- androidprv:digit="8"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key9"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- androidprv:textView="@+id/pinEntry"
- androidprv:digit="9"
- />
- </LinearLayout>
- <LinearLayout
- android:id="@+id/row4"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_gravity="center_horizontal"
- >
- <com.android.keyguard.NumPadButton
- android:id="@+id/delete_button"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- android:contentDescription="@string/keyboardview_keycode_delete"
- style="@style/NumPadKey.Delete"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key0"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/pinEntry"
- androidprv:digit="0"
- />
- <com.android.keyguard.NumPadButton
- android:id="@+id/key_enter"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- style="@style/NumPadKey.Enter"
- android:contentDescription="@string/keyboardview_keycode_enter"
- />
- </LinearLayout>
- </LinearLayout>
+
+ <androidx.constraintlayout.helper.widget.Flow
+ android:id="@+id/flow1"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:orientation="horizontal"
+
+ androidprv:constraint_referenced_ids="key1,key2,key3,key4,key5,key6,key7,key8,key9,delete_button,key0,key_enter"
+
+ androidprv:flow_horizontalGap="@dimen/num_pad_key_margin_end"
+
+ androidprv:flow_horizontalStyle="packed"
+ androidprv:flow_maxElementsWrap="3"
+
+ androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom"
+ androidprv:flow_verticalStyle="packed"
+ androidprv:flow_verticalBias="1.0"
+
+ androidprv:flow_wrapMode="aligned"
+
+ androidprv:layout_constraintTop_toTopOf="parent"
+ androidprv:layout_constraintBottom_toBottomOf="parent"
+ androidprv:layout_constraintEnd_toEndOf="parent"
+ androidprv:layout_constraintStart_toStartOf="parent" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key1"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ androidprv:digit="1"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key2"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ androidprv:digit="2"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key3"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ androidprv:digit="3"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key4"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ androidprv:digit="4"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key5"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ androidprv:digit="5"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key6"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ androidprv:digit="6"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key7"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ androidprv:digit="7"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key8"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ androidprv:digit="8"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key9"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ androidprv:digit="9"
+ androidprv:textView="@+id/pinEntry" />
+
+
+ <com.android.keyguard.NumPadButton
+ android:id="@+id/delete_button"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ style="@style/NumPadKey.Delete"
+ android:contentDescription="@string/keyboardview_keycode_delete"
+ />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key0"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ androidprv:digit="0"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadButton
+ android:id="@+id/key_enter"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ style="@style/NumPadKey.Enter"
+ android:contentDescription="@string/keyboardview_keycode_enter"
+ />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+
+
<include layout="@layout/keyguard_eca"
android:id="@+id/keyguard_selector_fade_container"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
index 1abd393..009b7cb 100644
--- a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
@@ -74,7 +74,7 @@
<string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Disable eSIM to use device without mobile service."</string>
<string name="kg_pin_instructions" msgid="822353548385014361">"Enter PIN"</string>
<string name="kg_password_instructions" msgid="324455062831719903">"Enter Password"</string>
- <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"SIM is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_puk_hint_multi" msgid="4876780689904862943">"SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\" is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_pin_hint" msgid="6028432138916150399">"Enter desired PIN code"</string>
<string name="kg_enter_confirm_pin_hint" msgid="4261064020391799132">"Confirm desired PIN code"</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
index c3e8e61..21f32cf 100644
--- a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
@@ -74,7 +74,7 @@
<string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Disable eSIM to use device without mobile service."</string>
<string name="kg_pin_instructions" msgid="822353548385014361">"Enter PIN"</string>
<string name="kg_password_instructions" msgid="324455062831719903">"Enter Password"</string>
- <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"SIM is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_puk_hint_multi" msgid="4876780689904862943">"SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\" is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_pin_hint" msgid="6028432138916150399">"Enter desired PIN code"</string>
<string name="kg_enter_confirm_pin_hint" msgid="4261064020391799132">"Confirm desired PIN code"</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
index 1abd393..009b7cb 100644
--- a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
@@ -74,7 +74,7 @@
<string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Disable eSIM to use device without mobile service."</string>
<string name="kg_pin_instructions" msgid="822353548385014361">"Enter PIN"</string>
<string name="kg_password_instructions" msgid="324455062831719903">"Enter Password"</string>
- <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"SIM is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_puk_hint_multi" msgid="4876780689904862943">"SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\" is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_pin_hint" msgid="6028432138916150399">"Enter desired PIN code"</string>
<string name="kg_enter_confirm_pin_hint" msgid="4261064020391799132">"Confirm desired PIN code"</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
index 1abd393..009b7cb 100644
--- a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
@@ -74,7 +74,7 @@
<string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Disable eSIM to use device without mobile service."</string>
<string name="kg_pin_instructions" msgid="822353548385014361">"Enter PIN"</string>
<string name="kg_password_instructions" msgid="324455062831719903">"Enter Password"</string>
- <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"SIM is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_puk_hint_multi" msgid="4876780689904862943">"SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\" is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_pin_hint" msgid="6028432138916150399">"Enter desired PIN code"</string>
<string name="kg_enter_confirm_pin_hint" msgid="4261064020391799132">"Confirm desired PIN code"</string>
diff --git a/packages/SystemUI/res-keyguard/values-land/donottranslate.xml b/packages/SystemUI/res-keyguard/values-land/donottranslate.xml
new file mode 100644
index 0000000..9912b69
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/values-land/donottranslate.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="num_pad_key_ratio">1.51</string>
+</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml
index 0b1efa8..fb2571e 100644
--- a/packages/SystemUI/res-keyguard/values-sv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml
@@ -61,7 +61,7 @@
<string name="error_disable_esim_msg" msgid="2441188596467999327">"Det gick inte att inaktivera eSIM-kortet på grund av ett fel."</string>
<string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Retur"</string>
<string name="kg_forgot_pattern_button_text" msgid="3304688032024541260">"Har du glömt ditt grafiska lösenord?"</string>
- <string name="kg_wrong_pattern" msgid="5907301342430102842">"Fel grafiskt lösenord"</string>
+ <string name="kg_wrong_pattern" msgid="5907301342430102842">"Fel mönster"</string>
<string name="kg_wrong_password" msgid="4143127991071670512">"Fel lösenord"</string>
<string name="kg_wrong_pin" msgid="4160978845968732624">"Fel pinkod"</string>
<plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="991400408675793914">
@@ -82,7 +82,7 @@
<string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Ange en pinkod med fyra till åtta siffror."</string>
<string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-koden ska vara minst åtta siffror."</string>
<string name="kg_invalid_puk" msgid="1774337070084931186">"Ange rätt PUK-kod. Om försöken upprepas inaktiveras SIM-kortet permanent."</string>
- <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"För många försök med grafiskt lösenord"</string>
+ <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"För många försök med mönster"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Du har angett fel pinkod <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
@@ -102,13 +102,13 @@
<string name="keyguard_carrier_default" msgid="6359808469637388586">"Ingen tjänst."</string>
<string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Byt inmatningsmetod"</string>
<string name="airplane_mode" msgid="2528005343938497866">"Flygplansläge"</string>
- <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Du måste ange grafiskt lösenord när du har startat om enheten"</string>
+ <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Du måste rita mönster när du har startat om enheten"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Du måste ange pinkod när du har startat om enheten"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Du måste ange lösenord när du har startat om enheten"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Du måste ange grafiskt lösenord för ytterligare säkerhet"</string>
+ <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Du måste rita mönster för ytterligare säkerhet"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Du måste ange pinkod för ytterligare säkerhet"</string>
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Du måste ange lösenord för ytterligare säkerhet"</string>
- <string name="kg_prompt_reason_switch_profiles_pattern" msgid="1922016914701991230">"Du måste ange grafiskt lösenord när du byter profil"</string>
+ <string name="kg_prompt_reason_switch_profiles_pattern" msgid="1922016914701991230">"Du måste rita mönster när du byter profil"</string>
<string name="kg_prompt_reason_switch_profiles_pin" msgid="6490434826361055400">"Du måste ange pinkod när du byter profil"</string>
<string name="kg_prompt_reason_switch_profiles_password" msgid="1680374696393804441">"Du måste ange lösenord när du byter profil"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administratören har låst enheten"</string>
diff --git a/packages/SystemUI/res-keyguard/values/donottranslate.xml b/packages/SystemUI/res-keyguard/values/donottranslate.xml
index a4d0ff7..878c017 100644
--- a/packages/SystemUI/res-keyguard/values/donottranslate.xml
+++ b/packages/SystemUI/res-keyguard/values/donottranslate.xml
@@ -26,4 +26,6 @@
<!-- Skeleton string format for displaying the time in 24-hour format. -->
<string name="clock_24hr_format">Hm</string>
+
+ <string name="num_pad_key_ratio">1</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 72b027a..ea769c6 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -37,6 +37,10 @@
<item name="android:colorControlNormal">@null</item>
<item name="android:colorControlHighlight">?android:attr/colorAccent</item>
<item name="android:background">@drawable/num_pad_key_background</item>
+
+ <!-- Default values for NumPadKey used in a ConstraintLayout. -->
+ <item name="layout_constraintDimensionRatio">@string/num_pad_key_ratio</item>
+ <item name="layout_constraintWidth_max">@dimen/num_pad_key_width</item>
</style>
<style name="Widget.TextView.NumPadKey.Digit"
parent="@android:style/Widget.DeviceDefault.TextView">
diff --git a/packages/SystemUI/res/drawable-nodpi/android_12.xml b/packages/SystemUI/res/drawable-nodpi/android_12.xml
new file mode 100644
index 0000000..bdeeced
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/android_12.xml
@@ -0,0 +1,37 @@
+<!--
+Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2 (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="48dp"
+ android:height="48dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
+ <group>
+ <clip-path
+ android:pathData="M14,14h21v20h-21z"/>
+ <path
+ android:pathData="M15,15C15.7956,15 16.5587,15.3161 17.1213,15.8787C17.6839,16.4413 18,17.2044 18,18V33"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#ffffff"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M34,33H22V30C22,28.4087 22.6321,26.8826 23.7574,25.7574C24.8826,24.6321 26.4087,24 28,24H31C31.7956,24 32.5587,23.6839 33.1213,23.1213C33.6839,22.5587 34,21.7957 34,21C34.009,19.5779 33.5126,18.1989 32.5993,17.1088C31.686,16.0188 30.4153,15.2885 29.0136,15.0483C27.612,14.8081 26.1706,15.0735 24.9464,15.7973C23.7223,16.5211 22.795,17.6561 22.33,19C22.2199,19.3261 22.1363,19.6605 22.08,20"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#ffffff"
+ android:strokeLineCap="round"/>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable-nodpi/icon.xml b/packages/SystemUI/res/drawable-nodpi/icon.xml
index 7f8d4fa..9972496 100644
--- a/packages/SystemUI/res/drawable-nodpi/icon.xml
+++ b/packages/SystemUI/res/drawable-nodpi/icon.xml
@@ -15,5 +15,5 @@
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/icon_bg"/>
- <foreground android:drawable="@drawable/android_11_dial"/>
+ <foreground android:drawable="@drawable/android_12"/>
</adaptive-icon>
diff --git a/packages/SystemUI/res/drawable-nodpi/icon_bg.xml b/packages/SystemUI/res/drawable-nodpi/icon_bg.xml
index 31b2a7f..ff7cbae 100644
--- a/packages/SystemUI/res/drawable-nodpi/icon_bg.xml
+++ b/packages/SystemUI/res/drawable-nodpi/icon_bg.xml
@@ -14,5 +14,5 @@
limitations under the License.
-->
<color xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="#073042" />
+ android:color="@android:color/system_accent1_500" />
diff --git a/packages/SystemUI/res/drawable/controls_icon.xml b/packages/SystemUI/res/drawable/controls_icon.xml
new file mode 100644
index 0000000..f1814a2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/controls_icon.xml
@@ -0,0 +1,25 @@
+<?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
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12,3L4,9v12h16L20,9l-8,-6zM18,19h-3v-6L9,13v6L6,19v-9l6,-4.5 6,4.5v9z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/wallet_lockscreen_bg.xml b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/wallet_lockscreen_bg.xml
rename to packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 9ce83a7..8dbd59d 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -82,18 +82,32 @@
<ImageView
android:id="@+id/wallet_button"
- android:layout_height="@dimen/keyguard_affordance_wallet_height"
- android:layout_width="@dimen/keyguard_affordance_wallet_width"
+ android:layout_height="@dimen/keyguard_affordance_fixed_height"
+ android:layout_width="@dimen/keyguard_affordance_fixed_width"
android:layout_gravity="bottom|end"
android:scaleType="center"
android:tint="?android:attr/textColorPrimary"
android:src="@drawable/ic_wallet_lockscreen"
- android:background="@drawable/wallet_lockscreen_bg"
+ android:background="@drawable/keyguard_bottom_affordance_bg"
android:layout_marginEnd="@dimen/keyguard_affordance_horizontal_offset"
android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
android:contentDescription="@string/accessibility_wallet_button"
android:visibility="gone" />
+ <ImageView
+ android:id="@+id/controls_button"
+ android:layout_height="@dimen/keyguard_affordance_fixed_height"
+ android:layout_width="@dimen/keyguard_affordance_fixed_width"
+ android:layout_gravity="bottom|start"
+ android:scaleType="center"
+ android:tint="?android:attr/textColorPrimary"
+ android:src="@drawable/controls_icon"
+ android:background="@drawable/keyguard_bottom_affordance_bg"
+ android:layout_marginStart="@dimen/keyguard_affordance_horizontal_offset"
+ android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
+ android:contentDescription="@string/quick_controls_title"
+ android:visibility="gone" />
+
<FrameLayout
android:id="@+id/overlay_container"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values-af/strings_tv.xml b/packages/SystemUI/res/values-af/strings_tv.xml
index 5420779..c20d01e 100644
--- a/packages/SystemUI/res/values-af/strings_tv.xml
+++ b/packages/SystemUI/res/values-af/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Kennisgewings"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Geen kennisgewings nie"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofoon neem tans op"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera neem tans op"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera en mikrofoon neem tans op"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofoon het opname gestop"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera het opname gestop"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera en mikrofoon het opname gestop"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings_tv.xml b/packages/SystemUI/res/values-am/strings_tv.xml
index ede0b78..39429e4 100644
--- a/packages/SystemUI/res/values-am/strings_tv.xml
+++ b/packages/SystemUI/res/values-am/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"በ<xliff:g id="VPN_APP">%1$s</xliff:g> በኩል"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"ማሳወቂያዎች"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"ምንም ማሳወቂያዎች የሉም"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"ማይክሮፎን እየቀዳ ነው"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"ካሜራ እየቀረጸ ነው"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"ካሜራ እየቀረጸ እና ማይክሮፎን እየቀዳ ነው"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"ማይክሮፎን መቅዳት አቁሟል"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"ካሜራ መቅረጽ አቁሟል"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"ካሜራ መቅረጽ እና ማይክሮፎን መቅዳት አቁመዋል"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings_tv.xml b/packages/SystemUI/res/values-ar/strings_tv.xml
index f6c4aef..13f23f0 100644
--- a/packages/SystemUI/res/values-ar/strings_tv.xml
+++ b/packages/SystemUI/res/values-ar/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"عبر <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"الإشعارات"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"ما من إشعارات"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"جارٍ التسجيل بالميكرفون"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"جارٍ التسجيل بالكاميرا"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"جارٍ التسجيل بالكاميرا والميكروفون"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"توقف التسجيل بالميكرفون."</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"توقف التسجيل بالكاميرا."</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"توقف التسجيل بالكاميرا والميكروفون."</string>
</resources>
diff --git a/packages/SystemUI/res/values-as/strings_tv.xml b/packages/SystemUI/res/values-as/strings_tv.xml
index 6ceee80..733e2e6 100644
--- a/packages/SystemUI/res/values-as/strings_tv.xml
+++ b/packages/SystemUI/res/values-as/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>ৰ জৰিয়তে"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"জাননী"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"কোনো জাননী নাই"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"মাইক্ৰ’ফ’নটোৱে ৰেক’ৰ্ড কৰি আছে"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"কেমেৰাটোৱে ৰেক’ৰ্ড কৰি আছে"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"কেমেৰা আৰু মাইক্ৰ’ফ’নটোৱে ৰেক’ৰ্ড কৰি আছে"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"মাইক্ৰ’ফ’নটোৱে ৰেক’ৰ্ড কৰাটো বন্ধ কৰিছে"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"কেমেৰাটোৱে ৰেক’ৰ্ড কৰাটো বন্ধ কৰিছে"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"কেমেৰা আৰু মাইক্ৰ’ফ’নটোৱে ৰেক’ৰ্ড কৰাটো বন্ধ কৰিছে"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az/strings_tv.xml b/packages/SystemUI/res/values-az/strings_tv.xml
index d141ad6..cd8b46c 100644
--- a/packages/SystemUI/res/values-az/strings_tv.xml
+++ b/packages/SystemUI/res/values-az/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> vasitəsilə"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Bildirişlər"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Bildiriş yoxdur"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon yazır"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera yazır"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera və mikrofon yazır"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofon yazmağı dayandırıb"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera yazmağı dayandırıb"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera və mikrofon yazmağı dayandırıb"</string>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml b/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
index 04a7e81..31a37db 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Preko: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Obaveštenja"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Nema obaveštenja"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon snima"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera snima"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera i mikrofon snimaju"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Snimanje mikrofonom je zaustavljeno"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Snimanje kamerom je zaustavljeno"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Snimanje kamerom i mikrofonom je zaustavljeno"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings_tv.xml b/packages/SystemUI/res/values-be/strings_tv.xml
index 5aa771f..410c120 100644
--- a/packages/SystemUI/res/values-be/strings_tv.xml
+++ b/packages/SystemUI/res/values-be/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Праз <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Апавяшчэнні"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Апавяшчэнняў няма"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Ідзе запіс з выкарыстаннем мікрафона"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Ідзе запіс з выкарыстаннем камеры"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Ідзе запіс з выкарыстаннем камеры і мікрафона"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Запіс з выкарыстаннем мікрафона спынены"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Запіс з выкарыстаннем камеры спынены"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Запіс з выкарыстаннем камеры і мікрафона спынены"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings_tv.xml b/packages/SystemUI/res/values-bg/strings_tv.xml
index 49bf014..981ab95 100644
--- a/packages/SystemUI/res/values-bg/strings_tv.xml
+++ b/packages/SystemUI/res/values-bg/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Чрез <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Известия"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Няма известия"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Микрофонът записва"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Камерата записва"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Камерата и микрофонът записват"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Микрофонът спря да записва"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Камерата спря да записва"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Камерата и микрофонът спряха да записват"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings_tv.xml b/packages/SystemUI/res/values-bn/strings_tv.xml
index 5a9b456..5d252b1 100644
--- a/packages/SystemUI/res/values-bn/strings_tv.xml
+++ b/packages/SystemUI/res/values-bn/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>-এর মাধ্যমে"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"বিজ্ঞপ্তি"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"কোনও বিজ্ঞপ্তি নেই"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"মাইক্রোফোনে রেকর্ড করা হচ্ছে"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"ক্যামেরায় রেকর্ড করা হচ্ছে"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"ক্যামেরা ও মাইক্রোফোনে রেকর্ড করা হচ্ছে"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"মাইক্রোফোনে রেকর্ড করা বন্ধ হয়ে গেছে"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"ক্যামেরায় রেকর্ড করা বন্ধ হয়ে গেছে"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"ক্যামেরা ও মাইক্রোফোনে রেকর্ড করা বন্ধ হয়ে গেছে"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings_tv.xml b/packages/SystemUI/res/values-bs/strings_tv.xml
index 92c5e2a..341c125 100644
--- a/packages/SystemUI/res/values-bs/strings_tv.xml
+++ b/packages/SystemUI/res/values-bs/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Putem: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Obavještenja"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Nema obavještenja"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon snima"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera snima"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera i mikrofon snimaju"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofon je prestao snimati"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera je prestala snimati"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera i mikrofon su prestali snimati"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings_tv.xml b/packages/SystemUI/res/values-ca/strings_tv.xml
index dac4a1a..6a28c83 100644
--- a/packages/SystemUI/res/values-ca/strings_tv.xml
+++ b/packages/SystemUI/res/values-ca/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Mitjançant <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notificacions"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Cap notificació"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"El micròfon està gravant"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"La càmera està gravant"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"La càmera i el micròfon estan gravant"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"El micròfon ha deixat de gravar"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"La càmera ha deixat de gravar"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"La càmera i el micròfon han deixat de gravar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings_tv.xml b/packages/SystemUI/res/values-cs/strings_tv.xml
index e9f4a10..115c875 100644
--- a/packages/SystemUI/res/values-cs/strings_tv.xml
+++ b/packages/SystemUI/res/values-cs/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Přes <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Oznámení"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Žádná oznámení"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon nahrává"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera nahrává"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera a mikrofon nahrávají"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofon přestal nahrávat"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera přestala nahrávat"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera a mikrofon přestaly nahrávat"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings_tv.xml b/packages/SystemUI/res/values-da/strings_tv.xml
index 9534776..af48946 100644
--- a/packages/SystemUI/res/values-da/strings_tv.xml
+++ b/packages/SystemUI/res/values-da/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notifikationer"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Ingen notifikationer"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofonen optager"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kameraet optager"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kameraet og mikrofonen optager"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofonen er stoppet med at optage"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kameraet er stoppet med at optage"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kameraet og mikrofonen er stoppet med at optage"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings_tv.xml b/packages/SystemUI/res/values-de/strings_tv.xml
index ec162ef..e8e8dcd 100644
--- a/packages/SystemUI/res/values-de/strings_tv.xml
+++ b/packages/SystemUI/res/values-de/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Über <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Benachrichtigungen"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Keine Benachrichtigungen"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon nimmt auf"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera nimmt auf"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera und Mikrofon nehmen auf"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Aufnahme des Mikrofons gestoppt"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Aufnahme der Kamera gestoppt"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Aufnahme von Kamera und Mikrofon gestoppt"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings_tv.xml b/packages/SystemUI/res/values-el/strings_tv.xml
index 175c402..01def2b 100644
--- a/packages/SystemUI/res/values-el/strings_tv.xml
+++ b/packages/SystemUI/res/values-el/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Μέσω <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Ειδοποιήσεις"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Δεν υπάρχουν ειδοποιήσεις."</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Πραγματοποιείται εγγραφή από το μικρόφωνο"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Πραγματοποιείται εγγραφή από την κάμερα"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Πραγματοποιείται εγγραφή από την κάμερα και το μικρόφωνο"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Η εγγραφή από το μικρόφωνο διακόπηκε"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Η εγγραφή από την κάμερα διακόπηκε"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Η εγγραφή από την κάμερα και το μικρόφωνο διακόπηκε"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 55b0f98..4520ed3 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -534,7 +534,7 @@
<string name="quick_settings_disclosure_named_management_vpns" msgid="4046375645500668555">"Este dispositivo pertenece a <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> y está conectado a VPN"</string>
<string name="quick_settings_disclosure_managed_profile_monitoring" msgid="1423899084754272514">"Tu organización puede controlar el tráfico de red en tu perfil de trabajo"</string>
<string name="quick_settings_disclosure_named_managed_profile_monitoring" msgid="8321469176706219860">"Es posible que <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> controle el tráfico de red en tu perfil de trabajo"</string>
- <string name="quick_settings_disclosure_managed_profile_network_activity" msgid="2636594621387832827">"El administrador de IT puede ver la actividad de red de tu perfil de trabajo"</string>
+ <string name="quick_settings_disclosure_managed_profile_network_activity" msgid="2636594621387832827">"El administrador de TI puede ver la actividad de red de tu perfil de trabajo"</string>
<string name="quick_settings_disclosure_monitoring" msgid="8548019955631378680">"Es posible que la red esté supervisada"</string>
<string name="quick_settings_disclosure_vpns" msgid="7213546797022280246">"Este dispositivo está conectado a VPN"</string>
<string name="quick_settings_disclosure_managed_profile_named_vpn" msgid="8117568745060010789">"Tu perfil de trabajo está conectado a <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings_tv.xml b/packages/SystemUI/res/values-es-rUS/strings_tv.xml
index 680e7cc..f2f0601 100644
--- a/packages/SystemUI/res/values-es-rUS/strings_tv.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"A través de <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notificaciones"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"No hay notificaciones"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"El micrófono está grabando"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"La cámara está grabando"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"La cámara y el micrófono están grabando"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"El micrófono dejó de grabar"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"La cámara dejó de grabar"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"La cámara y el micrófono dejaron de grabar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings_tv.xml b/packages/SystemUI/res/values-es/strings_tv.xml
index 16154a4..cc78cf2 100644
--- a/packages/SystemUI/res/values-es/strings_tv.xml
+++ b/packages/SystemUI/res/values-es/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"A través de <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notificaciones"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Sin notificaciones"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"El micrófono está grabando"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"La cámara está grabando"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"La cámara y el micrófono están grabando"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"El micrófono ha dejado de grabar"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"La cámara ha dejado de grabar"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"La cámara y el micrófono han dejado de grabar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings_tv.xml b/packages/SystemUI/res/values-et/strings_tv.xml
index 3732020..6f020c6 100644
--- a/packages/SystemUI/res/values-et/strings_tv.xml
+++ b/packages/SystemUI/res/values-et/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Teenuse <xliff:g id="VPN_APP">%1$s</xliff:g> kaudu"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Märguanded"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Märguandeid pole"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon salvestab"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kaamera salvestab"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kaamera ja mikrofon salvestavad"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofon peatas salvestamise"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kaamera peatas salvestamise"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kaamera ja mikrofon peatasid salvestamise"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings_tv.xml b/packages/SystemUI/res/values-eu/strings_tv.xml
index 524165e..c9c30c7 100644
--- a/packages/SystemUI/res/values-eu/strings_tv.xml
+++ b/packages/SystemUI/res/values-eu/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> bidez"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Jakinarazpenak"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Ez dago jakinarazpenik"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofonoa grabatzen ari da"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera grabatzen ari da"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera eta mikrofonoa grabatzen ari dira"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofonoak grabatzeari utzi dio"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamerak grabatzeari utzi dio"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamerak eta mikrofonoak grabatzeari utzi diote"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings_tv.xml b/packages/SystemUI/res/values-fa/strings_tv.xml
index 8038755..3ba9b4e 100644
--- a/packages/SystemUI/res/values-fa/strings_tv.xml
+++ b/packages/SystemUI/res/values-fa/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"ازطریق <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"اعلانها"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"اعلانی ندارید"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"میکروفون درحال ضبط کردن است"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"دوربین درحال ضبط کردن است"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"دوربین و میکروفون درحال ضبط کردن هستند"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"ضبط میکروفون متوقف شد"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"ضبط دوربین متوقف شد"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"ضبط دوربین و میکروفون متوقف شد"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings_tv.xml b/packages/SystemUI/res/values-fi/strings_tv.xml
index 17797d7..6312837 100644
--- a/packages/SystemUI/res/values-fi/strings_tv.xml
+++ b/packages/SystemUI/res/values-fi/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Palvelun <xliff:g id="VPN_APP">%1$s</xliff:g> kautta"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Ilmoitukset"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Ei ilmoituksia"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofoni tallentaa"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera kuvaa"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera ja mikrofoni tallentavat"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofoni lopetti tallentamisen"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera lopetti kuvaamisen"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera ja mikrofoni lopettivat tallentamisen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings_tv.xml b/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
index 7f45411..0925abe 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Par <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notifications"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Aucune notification"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Le microphone enregistre"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"L\'appareil photo enregistre"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"L\'appareil photo et le microphone enregistrent"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Le microphone a arrêté l\'enregistrement"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"L\'appareil photo a arrêté l\'enregistrement"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"L\'appareil photo et le microphone ont arrêté l\'enregistrement"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings_tv.xml b/packages/SystemUI/res/values-fr/strings_tv.xml
index 99bab80..3a33aad 100644
--- a/packages/SystemUI/res/values-fr/strings_tv.xml
+++ b/packages/SystemUI/res/values-fr/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notifications"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Aucune notification"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Le micro enregistre…"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"La caméra enregistre…"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"La caméra et le micro enregistrent…"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Le micro a arrêté l\'enregistrement"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"La caméra a arrêté l\'enregistrement"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"La caméra et le micro ont arrêté l\'enregistrement"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings_tv.xml b/packages/SystemUI/res/values-gl/strings_tv.xml
index 0d35c4d..679c21d 100644
--- a/packages/SystemUI/res/values-gl/strings_tv.xml
+++ b/packages/SystemUI/res/values-gl/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"A través de <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notificacións"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Non hai notificacións"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"O micrófono está gravando"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"A cámara está gravando"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"A cámara e o micrófono están gravando"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"O micrófono deixou de gravar"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"A cámara deixou de gravar"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"A cámara e o micrófono deixaron de gravar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 408e798..553924a 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -230,7 +230,7 @@
<string name="accessibility_battery_level" msgid="5143715405241138822">"બૅટરી <xliff:g id="NUMBER">%d</xliff:g> ટકા."</string>
<string name="accessibility_battery_level_with_estimate" msgid="4843119982547599452">"તમારા વપરાશના આધારે બૅટરી <xliff:g id="PERCENTAGE">%1$s</xliff:g> ટકા, જે લગભગ <xliff:g id="TIME">%2$s</xliff:g> સુધી ચાલે તેટલી બચી છે"</string>
<string name="accessibility_battery_level_charging" msgid="8892191177774027364">"બૅટરી ચાર્જ થઈ રહી છે, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
- <string name="accessibility_settings_button" msgid="2197034218538913880">"સિસ્ટમ સેટિંગ્સ."</string>
+ <string name="accessibility_settings_button" msgid="2197034218538913880">"સિસ્ટમ સેટિંગ."</string>
<string name="accessibility_notifications_button" msgid="3960913924189228831">"નોટિફિકેશન."</string>
<string name="accessibility_overflow_action" msgid="8555835828182509104">"બધી સૂચના જુઓ"</string>
<string name="accessibility_remove_notification" msgid="1641455251495815527">"સૂચના સાફ કરો."</string>
@@ -245,7 +245,7 @@
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"સૂચના કાઢી નાખી."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"નોટિફિકેશન શેડ."</string>
- <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ઝડપી સેટિંગ્સ."</string>
+ <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ઝડપી સેટિંગ."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"લૉક સ્ક્રીન."</string>
<string name="accessibility_desc_settings" msgid="6728577365389151969">"સેટિંગ"</string>
<string name="accessibility_desc_recent_apps" msgid="1748675199348914194">"ઝલક."</string>
@@ -315,7 +315,7 @@
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> વધુ સૂચના અંદર છે.</item>
</plurals>
<string name="notification_summary_message_format" msgid="5158219088501909966">"<xliff:g id="CONTACT_NAME">%1$s</xliff:g>: <xliff:g id="MESSAGE_CONTENT">%2$s</xliff:g>"</string>
- <string name="status_bar_notification_inspect_item_title" msgid="6818779631806163080">"સૂચનાઓની સેટિંગ્સ"</string>
+ <string name="status_bar_notification_inspect_item_title" msgid="6818779631806163080">"નોટિફિકેશન સેટિંગ"</string>
<string name="status_bar_notification_app_settings_title" msgid="5050006438806013903">"<xliff:g id="APP_NAME">%s</xliff:g> સેટિંગ"</string>
<string name="accessibility_rotation_lock_off" msgid="3880436123632448930">"સ્ક્રીન ઑટોમૅટિક રીતે ફરશે."</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"સ્ક્રીન લેન્ડસ્કેપ ઓરિએન્ટેશનમાં લૉક કરેલ છે."</string>
@@ -565,12 +565,12 @@
<string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"તમારી વ્યક્તિગત પ્રોફાઇલ <xliff:g id="VPN_APP">%1$s</xliff:g> સાથે કનેક્ટ કરેલ છે, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટો સહિતની તમારી નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે."</string>
<string name="monitoring_description_do_header_generic" msgid="6130190408164834986">"તમારું ડિવાઇસ <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> દ્વારા મેનેજ થાય છે."</string>
<string name="monitoring_description_do_header_with_name" msgid="2696255132542779511">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>, તમારા ઉપકરણનું સંચાલન કરવા માટે <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> નો ઉપયોગ કરે છે."</string>
- <string name="monitoring_description_do_body" msgid="7700878065625769970">"વ્યવસ્થાપક સેટિંગ્સ, કૉર્પોરેટ ઍક્સેસ, ઍપ્સ, તમારા ઉપકરણ સંબંદ્ધ ડેટા અને ઉપકરણની સ્થાન માહિતીનું નિરીક્ષણ અને સંચાલન કરી શકે છે."</string>
+ <string name="monitoring_description_do_body" msgid="7700878065625769970">"વ્યવસ્થાપક સેટિંગ, કૉર્પોરેટ ઍક્સેસ, ઍપ, તમારા ડિવાઇસ સંબંધિત ડેટા અને ડિવાઇસની સ્થાન માહિતીને મૉનિટર અને મેનેજ કરી શકે છે."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="1467280496376492558">" "</string>
<string name="monitoring_description_do_learn_more" msgid="645149183455573790">"વધુ જાણો"</string>
<string name="monitoring_description_do_body_vpn" msgid="7699280130070502303">"તમે <xliff:g id="VPN_APP">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિત તમારી નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="8292589617720435430">" "</string>
- <string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"VPNની સેટિંગ્સ ખોલો"</string>
+ <string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"VPN સેટિંગ ખોલો"</string>
<string name="monitoring_description_ca_cert_settings_separator" msgid="7107390013344435439">" "</string>
<string name="monitoring_description_ca_cert_settings" msgid="8329781950135541003">"વિશ્વસનીય ઓળખપત્ર ખોલો"</string>
<string name="monitoring_description_network_logging" msgid="577305979174002252">"તમારા વ્યવસ્થાપકે નેટવર્ક લૉગિંગ ચાલુ કર્યુ છે, જે તમારા ઉપકરણ પર ટ્રાફિકનું નિરીક્ષણ કરે છે.\n\nવધુ માહિતી માટે, તમારા વ્યવસ્થાપકનો સંપર્ક કરો."</string>
@@ -617,7 +617,7 @@
<string name="screen_pinning_start" msgid="7483998671383371313">"ઍપ પિન કરી"</string>
<string name="screen_pinning_exit" msgid="4553787518387346893">"ઍપ અનપિન કરી"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ને છુપાવીએ?"</string>
- <string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"તે સેટિંગ્સમાં તમે તેને ચાલુ કરશો ત્યારે આગલી વખતે ફરીથી દેખાશે."</string>
+ <string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"તે સેટિંગમાં તમે તેને ચાલુ કરશો ત્યારે આગલી વખતે ફરીથી દેખાશે."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"છુપાવો"</string>
<string name="stream_voice_call" msgid="7468348170702375660">"કૉલ કરો"</string>
<string name="stream_system" msgid="7663148785370565134">"સિસ્ટમ"</string>
@@ -655,7 +655,7 @@
<string name="system_ui_tuner" msgid="1471348823289954729">"સિસ્ટમ UI ટ્યૂનર"</string>
<string name="show_battery_percentage" msgid="6235377891802910455">"એમ્બેડ કરેલ બૅટરી ટકા બતાવો"</string>
<string name="show_battery_percentage_summary" msgid="9053024758304102915">"જ્યારે ચાર્જ ન થઈ રહ્યું હોય ત્યારે સ્ટેટસ બાર આયકનની અંદર બૅટરી સ્તર ટકા બતાવો"</string>
- <string name="quick_settings" msgid="6211774484997470203">"ઝડપી સેટિંગ્સ"</string>
+ <string name="quick_settings" msgid="6211774484997470203">"ઝડપી સેટિંગ"</string>
<string name="status_bar" msgid="4357390266055077437">"સ્ટેટસ બાર"</string>
<string name="overview" msgid="3522318590458536816">"ઝલક"</string>
<string name="demo_mode" msgid="263484519766901593">"સિસ્ટમ UI ડેમો મોડ"</string>
@@ -680,21 +680,21 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"તમે <xliff:g id="WHEN">%1$s</xliff:g> એ તમારો આગલો એલાર્મ સાંભળશો નહીં"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> વાગ્યે"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> એ"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"ઝડપી સેટિંગ્સ, <xliff:g id="TITLE">%s</xliff:g>."</string>
+ <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"ઝડપી સેટિંગ, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"હૉટસ્પૉટ"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"ઑફિસની પ્રોફાઇલ"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"કેટલાક માટે મજા પરંતુ બધા માટે નહીં"</string>
<string name="tuner_warning" msgid="1861736288458481650">"સિસ્ટમ UI ટ્યૂનર તમને Android વપરાશકર્તા ઇન્ટરફેસને ટ્વીક અને કસ્ટમાઇઝ કરવાની વધારાની રીતો આપે છે. ભાવિ રીલિઝેસમાં આ પ્રાયોગિક સુવિધાઓ બદલાઈ, ભંગ અથવા અદૃશ્ય થઈ શકે છે. સાવધાની સાથે આગળ વધો."</string>
<string name="tuner_persistent_warning" msgid="230466285569307806">"ભાવિ રીલિઝેસમાં આ પ્રાયોગિક સુવિધાઓ બદલાઈ, ભંગ અથવા અદૃશ્ય થઈ શકે છે. સાવધાની સાથે આગળ વધો."</string>
<string name="got_it" msgid="477119182261892069">"સમજાઈ ગયું"</string>
- <string name="tuner_toast" msgid="3812684836514766951">"અભિનંદન! સિસ્ટમ UI ટ્યૂનરને સેટિંગ્સમાં ઉમેરવામાં આવ્યું છે"</string>
- <string name="remove_from_settings" msgid="633775561782209994">"સેટિંગ્સમાંથી દૂર કરો"</string>
- <string name="remove_from_settings_prompt" msgid="551565437265615426">"સેટિંગ્સમાંથી સિસ્ટમ UI ટ્યૂનર દૂર કરી અને તેની તમામ સુવિધાઓનો ઉપયોગ કરવાનું બંધ કરીએ?"</string>
+ <string name="tuner_toast" msgid="3812684836514766951">"અભિનંદન! સિસ્ટમ UI ટ્યૂનરને સેટિંગમાં ઉમેરવામાં આવ્યું છે"</string>
+ <string name="remove_from_settings" msgid="633775561782209994">"સેટિંગમાંથી કાઢી નાખો"</string>
+ <string name="remove_from_settings_prompt" msgid="551565437265615426">"સેટિંગમાંથી સિસ્ટમ UI ટ્યૂનર કાઢી નાખી અને તેની તમામ સુવિધાઓનો ઉપયોગ કરવાનું બંધ કરીએ?"</string>
<string name="activity_not_found" msgid="8711661533828200293">"તમારા ઉપકરણ પર ઍપ્લિકેશન ઇન્સ્ટોલ થયેલ નથી"</string>
<string name="clock_seconds" msgid="8709189470828542071">"ઘડિયાળ સેકન્ડ બતાવો"</string>
<string name="clock_seconds_desc" msgid="2415312788902144817">"ઘડિયાળ સેકન્ડ સ્થિતિ બારમાં બતાવો. બૅટરીની આવરદા પર અસર કરી શકે છે."</string>
- <string name="qs_rearrange" msgid="484816665478662911">"ઝડપી સેટિંગ્સને ફરીથી ગોઠવો"</string>
- <string name="show_brightness" msgid="6700267491672470007">"ઝડપી સેટિંગ્સમાં તેજ બતાવો"</string>
+ <string name="qs_rearrange" msgid="484816665478662911">"ઝડપી સેટિંગને ફરીથી ગોઠવો"</string>
+ <string name="show_brightness" msgid="6700267491672470007">"ઝડપી સેટિંગમાં બ્રાઇટનેસ બતાવો"</string>
<string name="experimental" msgid="3549865454812314826">"પ્રાયોગિક"</string>
<string name="enable_bluetooth_title" msgid="866883307336662596">"બ્લૂટૂથ ચાલુ કરવુ છે?"</string>
<string name="enable_bluetooth_message" msgid="6740938333772779717">"તમારા ટેબ્લેટ સાથે કીબોર્ડ કનેક્ટ કરવા માટે, તમારે પહેલાં બ્લૂટૂથ ચાલુ કરવાની જરૂર પડશે."</string>
@@ -916,19 +916,19 @@
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"જગ્યા <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ટાઇલ ઉમેરી"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ટાઇલ કાઢી નાખી"</string>
- <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ઝડપી સેટિંગ્સ સંપાદક."</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ઝડપી સેટિંગ એડિટર."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> નોટિફિકેશન: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"સેટિંગ્સ ખોલો."</string>
- <string name="accessibility_quick_settings_expand" msgid="2609275052412521467">"ઝડપી સેટિંગ્સ ખોલો."</string>
- <string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"ઝડપી સેટિંગ્સ બંધ કરો."</string>
+ <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"સેટિંગ ખોલો."</string>
+ <string name="accessibility_quick_settings_expand" msgid="2609275052412521467">"ઝડપી સેટિંગ ખોલો."</string>
+ <string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"ઝડપી સેટિંગ બંધ કરો."</string>
<string name="accessibility_quick_settings_alarm_set" msgid="7237918261045099853">"એલાર્મ સેટ કર્યો."</string>
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> તરીકે સાઇન ઇન કર્યું"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"વપરાશકર્તા પસંદ કરો"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"કોઈ ઇન્ટરનેટ નથી"</string>
<string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"વિગતો ખોલો."</string>
<string name="accessibility_quick_settings_not_available" msgid="6860875849497473854">"<xliff:g id="REASON">%s</xliff:g>ને કારણે અનુપલબ્ધ છે"</string>
- <string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> સેટિંગ્સ ખોલો."</string>
- <string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"સેટિંગ્સનો ક્રમ સંપાદિત કરો."</string>
+ <string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> સેટિંગ ખોલો."</string>
+ <string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"સેટિંગના ક્રમમાં ફેરફાર કરો."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"પાવર મેનૂ"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> માંથી <xliff:g id="ID_1">%1$d</xliff:g> પૃષ્ઠ"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"લૉક સ્ક્રીન"</string>
@@ -986,7 +986,7 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"મોબાઇલ ડેટા બંધ કરીએ?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"તમને <xliff:g id="CARRIER">%s</xliff:g> મારફતે ડેટા અથવા ઇન્ટરનેટનો ઍક્સેસ મળશે નહીં. ઇન્ટરનેટ માત્ર વાઇ-ફાઇ દ્વારા ઉપલબ્ધ થશે."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"તમારા કૅરિઅર"</string>
- <string name="touch_filtered_warning" msgid="8119511393338714836">"એક ઍપ પરવાનગી વિનંતીને અસ્પષ્ટ કરતી હોવાને કારણે, સેટિંગ્સ તમારા પ્રતિસાદને ચકાસી શકતી નથી."</string>
+ <string name="touch_filtered_warning" msgid="8119511393338714836">"કોઈ ઍપ પરવાનગી વિનંતીને અસ્પષ્ટ કરતી હોવાને કારણે, સેટિંગ તમારા પ્રતિસાદને ચકાસી શકતું નથી."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g>ને <xliff:g id="APP_2">%2$s</xliff:g> સ્લાઇસ બતાવવાની મંજૂરી આપીએ?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- મારાથી <xliff:g id="APP">%1$s</xliff:g>ની માહિતી વાંચી શકાતી નથી"</string>
<string name="slice_permission_text_2" msgid="6758906940360746983">"- મારાથી <xliff:g id="APP">%1$s</xliff:g>ની અંદર ક્રિયાઓ કરી શકાતી નથી"</string>
diff --git a/packages/SystemUI/res/values-gu/strings_tv.xml b/packages/SystemUI/res/values-gu/strings_tv.xml
index c2c8ad6..e226503 100644
--- a/packages/SystemUI/res/values-gu/strings_tv.xml
+++ b/packages/SystemUI/res/values-gu/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> મારફતે"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"નોટિફિકેશન"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"કોઈ નોટિફિકેશન નથી"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"માઇક્રોફોનનું રેકોર્ડિંગ ચાલુ છે"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"કૅમેરાનું રેકોર્ડિંગ ચાલુ છે"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"કૅમેરા અને માઇક્રોફોનનું રેકોર્ડિંગ ચાલુ છે"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"માઇક્રોફોનનું રેકોર્ડિંગ બંધ થઈ ગયું"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"કૅમેરાનું રેકોર્ડિંગ બંધ થઈ ગયું"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"કૅમેરા અને માઇક્રોફોનનું રેકોર્ડિંગ બંધ થઈ ગયું"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings_tv.xml b/packages/SystemUI/res/values-hi/strings_tv.xml
index eb8f150..cc9a562 100644
--- a/packages/SystemUI/res/values-hi/strings_tv.xml
+++ b/packages/SystemUI/res/values-hi/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> के ज़रिए"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"सूचनाएं"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"कोई सूचना नहीं है"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"माइक्रोफ़ोन रिकॉर्ड कर रहा है"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"कैमरा रिकॉर्ड कर रहा है"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"कैमरा और माइक्रोफ़ोन रिकॉर्ड कर रहे हैं"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"माइक्रोफ़ोन ने रिकॉर्ड करना बंद कर दिया है"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"कैमरे ने रिकॉर्ड करना बंद कर दिया है"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"कैमरे और माइक्रोफ़ोन ने रिकॉर्ड करना बंद कर दिया है"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings_tv.xml b/packages/SystemUI/res/values-hr/strings_tv.xml
index 241195b..633847c 100644
--- a/packages/SystemUI/res/values-hr/strings_tv.xml
+++ b/packages/SystemUI/res/values-hr/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Putem mreže <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Obavijesti"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Nema obavijesti"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon snima"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera snima"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera i mikrofon snimaju"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofon je prestao snimati"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera je prestala snimati"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera i mikrofon prestali su snimati"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings_tv.xml b/packages/SystemUI/res/values-hu/strings_tv.xml
index e825584..97c375a 100644
--- a/packages/SystemUI/res/values-hu/strings_tv.xml
+++ b/packages/SystemUI/res/values-hu/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Ezzel: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Értesítések"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Nincs értesítés"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"A mikrofon felvételt készít…"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"A kamera felvételt készít…"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"A kamera és a mikrofon felvételt készít…"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"A mikrofon befejezte a felvételkészítést"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"A kamera befejezte a felvételkészítést"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"A kamera és a mikrofon befejezte a felvételkészítést"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings_tv.xml b/packages/SystemUI/res/values-hy/strings_tv.xml
index 0fab090..3f46b90 100644
--- a/packages/SystemUI/res/values-hy/strings_tv.xml
+++ b/packages/SystemUI/res/values-hy/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>-ի միջոցով"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Ծանուցումներ"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Ծանուցումներ չկան"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Խոսափողը ձայնագրում է"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Տեսախցիկը տեսագրում է"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Տեսախցիկն ու խոսափողը տեսաձայնագրում են"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Խոսափողն այլևս չի ձայնագրում"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Տեսախցիկն այլևս չի տեսագրում"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Տեսախցիկն ու խոսափողը այլևս չեն տեսաձայնագրում"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings_tv.xml b/packages/SystemUI/res/values-in/strings_tv.xml
index c787ca2..d58cdc8 100644
--- a/packages/SystemUI/res/values-in/strings_tv.xml
+++ b/packages/SystemUI/res/values-in/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Melalui <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notifikasi"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Tidak Ada Notifikasi"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon sedang merekam"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera sedang merekam"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera dan Mikrofon sedang merekam"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofon berhenti merekam"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera berhenti merekam"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera dan Mikrofon berhenti merekam"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is/strings_tv.xml b/packages/SystemUI/res/values-is/strings_tv.xml
index 6d7c91c..eb0f450 100644
--- a/packages/SystemUI/res/values-is/strings_tv.xml
+++ b/packages/SystemUI/res/values-is/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Í gegnum <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Tilkynningar"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Engar tilkynningar"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Hljóðnemi er að taka upp"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Myndavél er að taka upp"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Myndavél og hljóðnemi eru að taka upp"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Hljóðnemi er hættur að taka upp"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Myndavél er hætt að taka upp"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Myndavél og hljóðnemi eru hætt að taka upp"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings_tv.xml b/packages/SystemUI/res/values-it/strings_tv.xml
index c676029..45d3369 100644
--- a/packages/SystemUI/res/values-it/strings_tv.xml
+++ b/packages/SystemUI/res/values-it/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Tramite <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notifiche"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Nessuna notifica"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Registrazione in corso con il microfono"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Registrazione in corso con la fotocamera"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Registrazione in corso con fotocamera e microfono"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Registrazione con il microfono interrotta"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Registrazione con la fotocamera interrotta"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Registrazione con fotocamera e microfono interrotta"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings_tv.xml b/packages/SystemUI/res/values-iw/strings_tv.xml
index 46e61d0..5c091d3 100644
--- a/packages/SystemUI/res/values-iw/strings_tv.xml
+++ b/packages/SystemUI/res/values-iw/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"דרך <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"התראות"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"אין התראות"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"המיקרופון מקליט"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"המצלמה מקליטה"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"המצלמה והמיקרופון מקליטים"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"המיקרופון הפסיק להקליט"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"המצלמה הפסיקה להקליט"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"המצלמה והמיקרופון הפסיקו להקליט"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings_tv.xml b/packages/SystemUI/res/values-ja/strings_tv.xml
index 798caec..c37958f 100644
--- a/packages/SystemUI/res/values-ja/strings_tv.xml
+++ b/packages/SystemUI/res/values-ja/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> 経由"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"通知"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"通知はありません"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"マイクで録音しています"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"カメラで録画しています"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"カメラとマイクで録画、録音しています"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"マイクが録音を停止しました"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"カメラが録画を停止しました"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"カメラとマイクが録画、録音を停止しました"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings_tv.xml b/packages/SystemUI/res/values-ka/strings_tv.xml
index b158e5c..8db4b1b 100644
--- a/packages/SystemUI/res/values-ka/strings_tv.xml
+++ b/packages/SystemUI/res/values-ka/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>-ის მიერ"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"შეტყობინებები"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"შეტყობინებები არ არის"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"მიკროფონი იწერს"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"კამერა იწერს"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"კამერა და მიკროფონი იწერს"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"მიკროფონმა ჩაწერა შეწყვიტა"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"კამერამ ჩაწერა შეწყვიტა"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"კამერამ და მიკროფონმა ჩაწერა შეწყვიტა"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings_tv.xml b/packages/SystemUI/res/values-kk/strings_tv.xml
index 36440c9..a56b4aa 100644
--- a/packages/SystemUI/res/values-kk/strings_tv.xml
+++ b/packages/SystemUI/res/values-kk/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> арқылы жалғанған"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Хабарландырулар"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Хабарландырулар жоқ"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Микрофон жазып жатыр."</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Камера жазып жатыр."</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Камера мен микрофон жазып жатыр."</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Микрофон жазуды тоқтатты."</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Камера жазуды тоқтатты."</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Камера мен микрофон жазуды тоқтатты."</string>
</resources>
diff --git a/packages/SystemUI/res/values-km/strings_tv.xml b/packages/SystemUI/res/values-km/strings_tv.xml
index b04cc2b..c654e6d 100644
--- a/packages/SystemUI/res/values-km/strings_tv.xml
+++ b/packages/SystemUI/res/values-km/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"តាមរយៈ <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"ការជូនដំណឹង"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"គ្មានការជូនដំណឹងទេ"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"មីក្រូហ្វូនកំពុងថត"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"កាមេរ៉ាកំពុងថត"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"កាមេរ៉ា និងមីក្រូហ្វូនកំពុងថត"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"មីក្រូហ្វូនបានឈប់ថត"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"កាមេរ៉ាបានឈប់ថត"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"កាមេរ៉ា និងមីក្រូហ្វូនបានឈប់ថត"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings_tv.xml b/packages/SystemUI/res/values-kn/strings_tv.xml
index e4b3314..3955a09 100644
--- a/packages/SystemUI/res/values-kn/strings_tv.xml
+++ b/packages/SystemUI/res/values-kn/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> ಮೂಲಕ"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"ಅಧಿಸೂಚನೆಗಳು"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"ಯಾವುದೇ ಅಧಿಸೂಚನೆಗಳಿಲ್ಲ"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"ಮೈಕ್ರೊಫೋನ್ ರೆಕಾರ್ಡಿಂಗ್ ಆಗುತ್ತಿದೆ"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"ಕ್ಯಾಮರಾ ರೆಕಾರ್ಡಿಂಗ್ ಆಗುತ್ತಿದೆ"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"ಕ್ಯಾಮರಾ ಮತ್ತು ಮೈಕ್ರೊಫೋನ್ ರೆಕಾರ್ಡಿಂಗ್ ಆಗುತ್ತಿವೆ"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"ಮೈಕ್ರೊಫೋನ್ ರೆಕಾರ್ಡಿಂಗ್ ನಿಲ್ಲಿಸಿದೆ"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"ಕ್ಯಾಮರಾ ರೆಕಾರ್ಡಿಂಗ್ ನಿಲ್ಲಿಸಲಾಗಿದೆ"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"ಕ್ಯಾಮರಾ ಮತ್ತು ಮೈಕ್ರೊಫೋನ್ ರೆಕಾರ್ಡಿಂಗ್ ನಿಲ್ಲಿಸಿವೆ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 044086e..9aaea76 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -353,7 +353,7 @@
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"위치 사용 중지"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"카메라 액세스"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"마이크 액세스"</string>
- <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"허용됨"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"사용 가능"</string>
<string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"차단됨"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"미디어 기기"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
diff --git a/packages/SystemUI/res/values-ko/strings_tv.xml b/packages/SystemUI/res/values-ko/strings_tv.xml
index 8849265..b9fb537 100644
--- a/packages/SystemUI/res/values-ko/strings_tv.xml
+++ b/packages/SystemUI/res/values-ko/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>에 연결됨"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"알림"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"알림 없음"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"마이크 녹음 중"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"카메라 녹화 중"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"카메라 녹화 및 마이크 녹음 중"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"마이크 녹음 중단됨"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"카메라 녹화 중단됨"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"카메라 녹화 및 마이크 녹음 중단됨"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/tiles_states_strings.xml b/packages/SystemUI/res/values-ko/tiles_states_strings.xml
index 38c0185..b583f24 100644
--- a/packages/SystemUI/res/values-ko/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ko/tiles_states_strings.xml
@@ -48,8 +48,8 @@
</string-array>
<string-array name="tile_states_battery">
<item msgid="6311253873330062961">"이용 불가"</item>
- <item msgid="7838121007534579872">"꺼짐"</item>
- <item msgid="1578872232501319194">"켜짐"</item>
+ <item msgid="7838121007534579872">"사용 안함"</item>
+ <item msgid="1578872232501319194">"사용"</item>
</string-array>
<string-array name="tile_states_dnd">
<item msgid="467587075903158357">"이용 불가"</item>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 9c2929d..0a0bf4c 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -1017,8 +1017,8 @@
<string name="device_services" msgid="1549944177856658705">"Түзмөк кызматтары"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Аталышы жок"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Жылдыруу"</string>
- <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Тутум чабыттоосу жаңырды. Өзгөртүү үчүн, Жөндөөлөргө өтүңүз."</string>
- <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Тутум чабыттоосун жаңыртуу үчүн Жөндөөлөргө өтүңүз"</string>
+ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Тутум чабыттоосу жаңырды. Өзгөртүү үчүн, жөндөөлөргө өтүңүз."</string>
+ <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Тутум чабыттоосун жаңыртуу үчүн жөндөөлөргө өтүңүз"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Көшүү режими"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Чоңойтуу терезеси"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Чоңойтуу терезесин башкаруу каражаттары"</string>
diff --git a/packages/SystemUI/res/values-ky/strings_tv.xml b/packages/SystemUI/res/values-ky/strings_tv.xml
index 128c7e0..52b2375 100644
--- a/packages/SystemUI/res/values-ky/strings_tv.xml
+++ b/packages/SystemUI/res/values-ky/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> аркылуу"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Билдирмелер"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Билдирме жок"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Микрофон жаздырууда"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Камера жаздырууда"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Камера менен микрофон жаздырууда"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Микрофон жаздырууну токтотту"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Камера жаздырууну токтотту"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Камера менен микрофон жаздырууну токтотту"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings_tv.xml b/packages/SystemUI/res/values-lo/strings_tv.xml
index b852456..d2de125 100644
--- a/packages/SystemUI/res/values-lo/strings_tv.xml
+++ b/packages/SystemUI/res/values-lo/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"ຜ່ານ <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"ການແຈ້ງເຕືອນ"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"ບໍ່ມີການແຈ້ງເຕືອນ"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"ໄມໂຄຣໂຟນກຳລັງບັນທຶກ"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"ກ້ອງຖ່າຍຮູບກຳລັງບັນທຶກ"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"ກ້ອງຖ່າຍຮູບ ແລະ ໄມໂຄຣໂຟນກຳລັງບັນທຶກ"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"ໄມໂຄຣໂຟນຢຸດການບັນທຶກແລ້ວ"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"ກ້ອງຖ່າຍຮູບຢຸດການບັນທຶກແລ້ວ"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"ກ້ອງຖ່າຍຮູບ ແລະ ໄມໂຄຣໂຟນຢຸດການບັນທຶກແລ້ວ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings_tv.xml b/packages/SystemUI/res/values-lt/strings_tv.xml
index 7cd7507..df23a61 100644
--- a/packages/SystemUI/res/values-lt/strings_tv.xml
+++ b/packages/SystemUI/res/values-lt/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Per „<xliff:g id="VPN_APP">%1$s</xliff:g>“"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Pranešimai"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Nėra jokių pranešimų"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofonas įrašo"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera įrašo"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera ir mikrofonas įrašo"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofonas nebeįrašo"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera nebeįrašo"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera ir mikrofonas nebeįrašo"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings_tv.xml b/packages/SystemUI/res/values-lv/strings_tv.xml
index 4c64843..e343a77 100644
--- a/packages/SystemUI/res/values-lv/strings_tv.xml
+++ b/packages/SystemUI/res/values-lv/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Izmantojot: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Paziņojumi"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Nav paziņojumu"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Notiek ierakstīšana ar mikrofonu"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Notiek ierakstīšana ar kameru"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Notiek ierakstīšana ar kameru un mikrofonu"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Ierakstīšana ar mikrofonu apturēta"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Ierakstīšana ar kameru apturēta"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Ierakstīšana ar kameru un mikrofonu apturēta"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 5317bca..9a8de86 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -243,7 +243,7 @@
<skip />
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
- <string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Известувањето е отфрлено."</string>
+ <string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Известувањето е отфрлено"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Панел за известување"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Брзи поставки."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Заклучи екран."</string>
diff --git a/packages/SystemUI/res/values-mk/strings_tv.xml b/packages/SystemUI/res/values-mk/strings_tv.xml
index 55d9df7..f39f1fa 100644
--- a/packages/SystemUI/res/values-mk/strings_tv.xml
+++ b/packages/SystemUI/res/values-mk/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Преку <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Известувања"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Нема известувања"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Микрофонот снима"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Камерата снима"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Камерата и микрофонот снимаат"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Микрофонот прекина со снимање"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Камерата прекина со снимање"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Камерата и микрофонот прекинаа со снимање"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings_tv.xml b/packages/SystemUI/res/values-ml/strings_tv.xml
index 6ae342cf..50d0280 100644
--- a/packages/SystemUI/res/values-ml/strings_tv.xml
+++ b/packages/SystemUI/res/values-ml/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> വഴി"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"അറിയിപ്പുകൾ"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"അറിയിപ്പുകൾ ഒന്നുമില്ല"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"മൈക്രോഫോൺ റെക്കോർഡ് ചെയ്യുകയാണ്"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"ക്യാമറ റെക്കോർഡ് ചെയ്യുകയാണ്"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"ക്യാമറയും മൈക്രോഫോണും റെക്കോർഡ് ചെയ്യുകയാണ്"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"മൈക്രോഫോൺ റെക്കോർഡ് ചെയ്യുന്നത് നിർത്തി"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"ക്യാമറ റെക്കോർഡ് ചെയ്യുന്നത് നിർത്തി"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"ക്യാമറയും മൈക്രോഫോണും റെക്കോർഡ് ചെയ്യുന്നത് നിർത്തി"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings_tv.xml b/packages/SystemUI/res/values-mn/strings_tv.xml
index bbb302f..1b20d84 100644
--- a/packages/SystemUI/res/values-mn/strings_tv.xml
+++ b/packages/SystemUI/res/values-mn/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>-р"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Мэдэгдэл"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Мэдэгдэл байхгүй байна"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Микрофон бичиж байна"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Камер бичиж байна"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Камер болон микрофон бичиж байна"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Микрофон бичихээ зогсоосон"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Камер бичихээ зогсоосон"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Камер болон микрофон бичихээ зогсоосон"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings_tv.xml b/packages/SystemUI/res/values-mr/strings_tv.xml
index d596d95..2d79d4a 100644
--- a/packages/SystemUI/res/values-mr/strings_tv.xml
+++ b/packages/SystemUI/res/values-mr/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> द्वारे"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"सूचना"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"सूचना नाहीत"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"मायक्रोफोन रेकॉर्ड करत आहे"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"कॅमेरा रेकॉर्ड करत आहे"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"कॅमेरा आणि मायक्रोफोन रेकॉर्ड करत आहेत"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"मायक्रोफोनने रेकॉर्ड करणे थांबवले"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"कॅमेराने रेकॉर्ड करणे थांबवले"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"कॅमेरा आणि मायक्रोफोनने रेकॉर्ड करणे थांबवले"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings_tv.xml b/packages/SystemUI/res/values-ms/strings_tv.xml
index e28d032..9064ec4 100644
--- a/packages/SystemUI/res/values-ms/strings_tv.xml
+++ b/packages/SystemUI/res/values-ms/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Melalui <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Pemberitahuan"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Tiada Pemberitahuan"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon sedang merakam"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera sedang merakam"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera dan Mikrofon sedang merakam"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofon berhenti merakam"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera berhenti merakam"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera dan Mikrofon berhenti merakam"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my/strings_tv.xml b/packages/SystemUI/res/values-my/strings_tv.xml
index 848c403..1aca9eb 100644
--- a/packages/SystemUI/res/values-my/strings_tv.xml
+++ b/packages/SystemUI/res/values-my/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> မှတစ်ဆင့်"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"အကြောင်းကြားချက်များ"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"အကြောင်းကြားချက်များ မရှိပါ"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"မိုက်ခရိုဖုန်း မှတ်တမ်းတင်နေသည်"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"ကင်မရာ မှတ်တမ်းတင်နေသည်"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"ကင်မရာနှင့် မိုက်ခရိုဖုန်းက မှတ်တမ်းတင်နေသည်"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"မိုက်ခရိုဖုန်း မှတ်တမ်းတင်ခြင်းကို ရပ်ထားသည်"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"ကင်မရာ မှတ်တမ်းတင်ခြင်းကို ရပ်ထားသည်"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"ကင်မရာနှင့် မိုက်ခရိုဖုန်းက မှတ်တမ်းတင်ခြင်းကို ရပ်ထားသည်"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings_tv.xml b/packages/SystemUI/res/values-nb/strings_tv.xml
index 11de50a..7eb6a29 100644
--- a/packages/SystemUI/res/values-nb/strings_tv.xml
+++ b/packages/SystemUI/res/values-nb/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Varsler"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Ingen varsler"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofonen tar opp"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kameraet tar opp"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kameraet og mikrofonen tar opp"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofonen stoppet opptaket"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kameraet stoppet opptaket"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kameraet og mikrofonen stoppet opptaket"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings_tv.xml b/packages/SystemUI/res/values-ne/strings_tv.xml
index 0bcc1cc..410f26f 100644
--- a/packages/SystemUI/res/values-ne/strings_tv.xml
+++ b/packages/SystemUI/res/values-ne/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> मार्फत"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"सूचनाहरू"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"कुनै पनि सूचना छैन"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"माइक्रोफोनले रेकर्ड गर्दै छ"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"क्यामेराले रेकर्ड गर्दै छ"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"क्यामेरा र माइक्रोफोनले रेकर्ड गर्दै छन्"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"माइक्रोफोनले रेकर्ड गर्न छाड्यो"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"क्यामेराले रेकर्ड गर्न छाड्यो"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"क्यामेरा र माइक्रोफोनले रेकर्ड गर्न छाडे"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings_tv.xml b/packages/SystemUI/res/values-nl/strings_tv.xml
index 02c00ec..7aeeabf 100644
--- a/packages/SystemUI/res/values-nl/strings_tv.xml
+++ b/packages/SystemUI/res/values-nl/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Meldingen"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Geen meldingen"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Microfoon neemt op"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Camera neemt op"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Camera en microfoon nemen op"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Microfoon neemt niet meer op"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Camera neemt niet meer op"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Camera en microfoon nemen niet meer op"</string>
</resources>
diff --git a/packages/SystemUI/res/values-or/strings_tv.xml b/packages/SystemUI/res/values-or/strings_tv.xml
index 8289068..2669a5a 100644
--- a/packages/SystemUI/res/values-or/strings_tv.xml
+++ b/packages/SystemUI/res/values-or/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> ମାଧ୍ୟମରେ"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"କୌଣସି ବିଜ୍ଞପ୍ତି ନାହିଁ"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"ମାଇକ୍ରୋଫୋନ୍ ରେକର୍ଡିଂ କରୁଛି"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"କ୍ୟାମେରା ରେକର୍ଡିଂ କରୁଛି"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"କ୍ୟାମେରା ଏବଂ ମାଇକ୍ରୋଫୋନ୍ ରେକର୍ଡିଂ କରୁଛି"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"ମାଇକ୍ରୋଫୋନ୍ ରେକର୍ଡିଂ ବନ୍ଦ କରିଛି"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"କ୍ୟାମେରା ରେକର୍ଡିଂ ବନ୍ଦ କରିଛି"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"କ୍ୟାମେରା ଏବଂ ମାଇକ୍ରୋଫୋନ୍ ରେକର୍ଡିଂ ବନ୍ଦ କରିଛି"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings_tv.xml b/packages/SystemUI/res/values-pa/strings_tv.xml
index 22fcce8..3443cfa 100644
--- a/packages/SystemUI/res/values-pa/strings_tv.xml
+++ b/packages/SystemUI/res/values-pa/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> ਰਾਹੀਂ"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"ਸੂਚਨਾਵਾਂ"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"ਕੋਈ ਸੂਚਨਾ ਨਹੀਂ"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਰਿਕਾਰਡ ਕਰ ਰਿਹਾ ਹੈ"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"ਕੈਮਰਾ ਰਿਕਾਰਡ ਕਰ ਰਿਹਾ ਹੈ"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"ਕੈਮਰਾ ਅਤੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਰਿਕਾਰਡ ਕਰ ਰਹੇ ਹਨ"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਨੇ ਰਿਕਾਰਡ ਕਰਨਾ ਬੰਦ ਕਰ ਦਿੱਤਾ ਹੈ"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"ਕੈਮਰੇ ਨੇ ਰਿਕਾਰਡ ਕਰਨਾ ਬੰਦ ਕਰ ਦਿੱਤਾ ਹੈ"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"ਕੈਮਰੇ ਅਤੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਨੇ ਰਿਕਾਰਡ ਕਰਨਾ ਬੰਦ ਕਰ ਦਿੱਤਾ ਹੈ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings_tv.xml b/packages/SystemUI/res/values-pl/strings_tv.xml
index 2371b5e..12b3777 100644
--- a/packages/SystemUI/res/values-pl/strings_tv.xml
+++ b/packages/SystemUI/res/values-pl/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Przez: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Powiadomienia"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Brak powiadomień"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon rejestruje"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Aparat rejestruje"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Aparat i mikrofon rejestrują"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofon przestał rejestrować"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Aparat przestał rejestrować"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Aparat i mikrofon przestały rejestrować"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings_tv.xml b/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
index 883fa3a..3ae7daf 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Através de <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notificações"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Sem notificações"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"O microfone está a gravar"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"A câmara está a gravar"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"A câmara e o microfone estão a gravar"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"O microfone parou a gravação"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"A câmara parou a gravação"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"A câmara e o microfone pararam a gravação"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings_tv.xml b/packages/SystemUI/res/values-ro/strings_tv.xml
index 9f28693..54dd985 100644
--- a/packages/SystemUI/res/values-ro/strings_tv.xml
+++ b/packages/SystemUI/res/values-ro/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Prin <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notificări"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Nicio notificare"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Microfonul înregistrează"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Camera foto înregistrează"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Camera foto și microfonul înregistrează"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Microfonul nu mai înregistrează"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Camera foto a oprit înregistrarea"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Camera foto și microfonul nu mai înregistrează"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings_tv.xml b/packages/SystemUI/res/values-ru/strings_tv.xml
index e2162ea..befb5d2 100644
--- a/packages/SystemUI/res/values-ru/strings_tv.xml
+++ b/packages/SystemUI/res/values-ru/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Через приложение <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Уведомления"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Уведомлений нет."</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Выполняется запись с микрофона"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Выполняется запись с камеры"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Выполняется запись с камеры и микрофона"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Запись с микрофона остановлена"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Запись с камеры остановлена"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Запись с камеры и микрофона остановлена"</string>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings_tv.xml b/packages/SystemUI/res/values-si/strings_tv.xml
index b750988..92257c7 100644
--- a/packages/SystemUI/res/values-si/strings_tv.xml
+++ b/packages/SystemUI/res/values-si/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> හරහා"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"දැනුම්දීම්"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"දැනුම්දීම් නැත"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"මයික්රෆෝනය පටිගත කරයි"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"කැමරාව පටිගත කරයි"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"කැමරාව සහ මයික්රෆෝනය පටිගත කරයි"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"මයික්රෆෝනය පටිගත කිරීම නැවැත්වීය"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"කැමරාව පටිගත කිරීම නැවැත්වීය"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"කැමරාව සහ මයික්රෆෝනය පටිගත කිරීම නැවැත්වීය"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings_tv.xml b/packages/SystemUI/res/values-sk/strings_tv.xml
index 2b74267..6910079 100644
--- a/packages/SystemUI/res/values-sk/strings_tv.xml
+++ b/packages/SystemUI/res/values-sk/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Cez: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Upozornenia"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Žiadne upozornenia"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofón nahráva"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera nahráva"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera a mikrofón nahrávajú"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofón prestal nahrávať"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera prestala nahrávať"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera a mikrofón prestali nahrávať"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings_tv.xml b/packages/SystemUI/res/values-sl/strings_tv.xml
index 2ef9705..1005079 100644
--- a/packages/SystemUI/res/values-sl/strings_tv.xml
+++ b/packages/SystemUI/res/values-sl/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Prek storitve <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Obvestila"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Ni obvestil"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Snemanje z mikrofonom"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Snemanje s fotoaparatom"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Snemanje s fotoaparatom in mikrofonom"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Ustavljeno snemanje z mikrofonom"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Ustavljeno snemanje s fotoaparatom"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Ustavljeno snemanje s fotoaparatom in mikrofonom"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings_tv.xml b/packages/SystemUI/res/values-sq/strings_tv.xml
index ece5982..c5ce631 100644
--- a/packages/SystemUI/res/values-sq/strings_tv.xml
+++ b/packages/SystemUI/res/values-sq/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Nëpërmjet <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Njoftimet"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Asnjë njoftim"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"\"Mikrofoni\" po regjistron"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"\"Kamera\" po regjistron"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"\"Kamera\" dhe \"Mikrofoni\" po regjistrojnë"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"\"Mikrofoni\" ndaloi së regjistruari"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"\"Kamera\" ndaloi së regjistruari"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"\"Kamera\" dhe \"Mikrofoni\" ndaluan së regjistruari"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings_tv.xml b/packages/SystemUI/res/values-sr/strings_tv.xml
index 38b106b..d35ff3c 100644
--- a/packages/SystemUI/res/values-sr/strings_tv.xml
+++ b/packages/SystemUI/res/values-sr/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Преко: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Обавештења"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Нема обавештења"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Микрофон снима"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Камера снима"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Камера и микрофон снимају"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Снимање микрофоном је заустављено"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Снимање камером је заустављено"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Снимање камером и микрофоном је заустављено"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 1f60b3a..c27cd83 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -158,21 +158,21 @@
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Slutför genom att trycka på Bekräfta"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentiserad"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Använd pinkod"</string>
- <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Använd grafiskt lösenord"</string>
+ <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Använd mönster"</string>
<string name="biometric_dialog_use_password" msgid="3445033859393474779">"Använd lösenord"</string>
<string name="biometric_dialog_wrong_pin" msgid="1878539073972762803">"Fel pinkod"</string>
- <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Fel grafiskt lösenord"</string>
+ <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Fel mönster"</string>
<string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Fel lösenord"</string>
<string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"För många felaktiga försök.\nFörsök igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
<string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Försök igen. Försök <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> av <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
<string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Din data raderas."</string>
- <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Enhetens data raderas om du anger fel grafiskt lösenord vid nästa försök."</string>
+ <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Enhetens data raderas om du ritar fel mönster vid nästa försök."</string>
<string name="biometric_dialog_last_pin_attempt_before_wipe_device" msgid="9151756675698215723">"Enhetens data raderas om du anger fel pinkod vid nästa försök."</string>
<string name="biometric_dialog_last_password_attempt_before_wipe_device" msgid="2363778585575998317">"Enhetens data raderas om du anger fel lösenord vid nästa försök."</string>
- <string name="biometric_dialog_last_pattern_attempt_before_wipe_user" msgid="8400180746043407270">"Användaren raderas om du anger fel grafiskt lösenord vid nästa försök."</string>
+ <string name="biometric_dialog_last_pattern_attempt_before_wipe_user" msgid="8400180746043407270">"Användaren raderas om du ritar fel mönster vid nästa försök."</string>
<string name="biometric_dialog_last_pin_attempt_before_wipe_user" msgid="4159878829962411168">"Användaren raderas om du anger fel pinkod vid nästa försök."</string>
<string name="biometric_dialog_last_password_attempt_before_wipe_user" msgid="4695682515465063885">"Den här användaren raderas om du anger fel lösenord vid nästa försök."</string>
- <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Jobbprofilen och dess data raderas om du anger fel grafiskt lösenord vid nästa försök."</string>
+ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Jobbprofilen och dess data raderas om du ritar fel mönster vid nästa försök."</string>
<string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Jobbprofilen och dess data raderas om du anger fel pinkod vid nästa försök."</string>
<string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Din jobbprofil och dess data raderas om du anger fel lösenord vid nästa försök."</string>
<string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"För många felaktiga försök. Enhetens data raderas."</string>
diff --git a/packages/SystemUI/res/values-sv/strings_tv.xml b/packages/SystemUI/res/values-sv/strings_tv.xml
index 22f6baa..346d5d2 100644
--- a/packages/SystemUI/res/values-sv/strings_tv.xml
+++ b/packages/SystemUI/res/values-sv/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Aviseringar"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Inga aviseringar"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofonen spelar in"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kameran spelar in"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kameran och mikrofonen spelar in"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofonen slutade spela in"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kameran slutade spela in"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kameran och mikrofonen slutade spelade in"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings_tv.xml b/packages/SystemUI/res/values-sw/strings_tv.xml
index 086a098..a585e69 100644
--- a/packages/SystemUI/res/values-sw/strings_tv.xml
+++ b/packages/SystemUI/res/values-sw/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Kupitia <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Arifa"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Hakuna Arifa"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Maikrofoni inarekodi"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera inarekodi"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera na Maikrofoni zinarekodi"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Maikrofoni imeacha kurekodi"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera imeacha kurekodi"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera na Maikrofoni zimeacha kurekodi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp-land/config.xml b/packages/SystemUI/res/values-sw600dp-land/config.xml
index 369e45c..ab159e1 100644
--- a/packages/SystemUI/res/values-sw600dp-land/config.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/config.xml
@@ -18,10 +18,18 @@
<!-- Max number of columns for quick controls area -->
<integer name="controls_max_columns">2</integer>
- <integer name="quick_settings_num_columns">2</integer>
+ <!-- The maximum number of rows in the QuickQSPanel -->
<integer name="quick_qs_panel_max_rows">4</integer>
+
+ <!-- The maximum number of tiles in the QuickQSPanel -->
<integer name="quick_qs_panel_max_tiles">8</integer>
<!-- Whether to use the split 2-column notification shade -->
<bool name="config_use_split_notification_shade">true</bool>
+
+ <!-- The number of columns in the QuickSettings -->
+ <integer name="quick_settings_num_columns">2</integer>
+
+ <!-- Notifications are sized to match the width of two (of 4) qs tiles in landscape. -->
+ <bool name="config_skinnyNotifsInLandscape">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 942cb2b..45b5afa 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -40,4 +40,8 @@
<!-- How many lines to show in the security footer -->
<integer name="qs_security_footer_maxLines">1</integer>
+
+ <!-- Determines whether to allow the nav bar handle to be forced to be opaque. -->
+ <bool name="allow_force_nav_bar_handle_opaque">false</bool>
+
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings_tv.xml b/packages/SystemUI/res/values-ta/strings_tv.xml
index 398ffe9..1dc581d 100644
--- a/packages/SystemUI/res/values-ta/strings_tv.xml
+++ b/packages/SystemUI/res/values-ta/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> வழியாக"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"அறிவிப்புகள்"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"அறிவிப்புகள் எதுவுமில்லை"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"மைக்ரோஃபோன் ரெக்கார்டு செய்கிறது"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"கேமரா ரெக்கார்டு செய்கிறது"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"கேமராவும் மைக்ரோஃபோனும் ரெக்கார்டு செய்கின்றன"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"மைக்ரோஃபோன் ரெக்கார்டு செய்வதை நிறுத்திவிட்டது"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"கேமரா ரெக்கார்டு செய்வதை நிறுத்திவிட்டது"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"கேமராவும் மைக்ரோஃபோனும் ரெக்கார்டு செய்வதை நிறுத்திவிட்டன"</string>
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 020d9b4..b8a3ccd 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -957,7 +957,7 @@
<string name="tuner_right" msgid="8247571132790812149">"కుడి"</string>
<string name="tuner_menu" msgid="363690665924769420">"మెనూ"</string>
<string name="tuner_app" msgid="6949280415826686972">"<xliff:g id="APP">%1$s</xliff:g> అనురవర్తనం"</string>
- <string name="notification_channel_alerts" msgid="3385787053375150046">"హెచ్చరికలు"</string>
+ <string name="notification_channel_alerts" msgid="3385787053375150046">"అలర్ట్లు"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"బ్యాటరీ"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"స్క్రీన్షాట్లు"</string>
<string name="notification_channel_general" msgid="4384774889645929705">"సాధారణ సందేశాలు"</string>
diff --git a/packages/SystemUI/res/values-te/strings_tv.xml b/packages/SystemUI/res/values-te/strings_tv.xml
index 33c9ec9..7eded1e 100644
--- a/packages/SystemUI/res/values-te/strings_tv.xml
+++ b/packages/SystemUI/res/values-te/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> ద్వారా"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"నోటిఫికేషన్లు"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"నోటిఫికేషన్లు లేవు"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"మైక్రోఫోన్ రికార్డింగ్ చేస్తోంది"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"కెమెరా రికార్డింగ్ చేస్తోంది"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"కెమెరా, మైక్రోఫోన్ రికార్డింగ్ చేస్తున్నాయి"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"మైక్రోఫోన్ రికార్డింగ్ చేయడం ఆపివేసింది"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"కెమెరా రికార్డింగ్ చేయడం ఆపివేసింది"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"కెమెరా, మైక్రోఫోన్ రికార్డింగ్ చేయడం ఆపివేశాయి"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index ce469f7..e8a6c16 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -353,7 +353,7 @@
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"ปิดตำแหน่ง"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"สิทธิ์เข้าถึงกล้อง"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"สิทธิ์เข้าถึงไมโครโฟน"</string>
- <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"มี"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"พร้อมให้ใช้งาน"</string>
<string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"ถูกบล็อก"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"อุปกรณ์สื่อ"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
diff --git a/packages/SystemUI/res/values-th/strings_tv.xml b/packages/SystemUI/res/values-th/strings_tv.xml
index 57cff1f..458dc7e 100644
--- a/packages/SystemUI/res/values-th/strings_tv.xml
+++ b/packages/SystemUI/res/values-th/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"ผ่าน <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"การแจ้งเตือน"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"ไม่มีการแจ้งเตือน"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"ไมโครโฟนกำลังบันทึก"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"กล้องกำลังบันทึก"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"กล้องและไมโครโฟนกำลังบันทึก"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"ไมโครโฟนหยุดบันทึกแล้ว"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"กล้องหยุดบันทึกแล้ว"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"กล้องและไมโครโฟนหยุดบันทึกแล้ว"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings_tv.xml b/packages/SystemUI/res/values-tl/strings_tv.xml
index 8be6a86..b45d62b 100644
--- a/packages/SystemUI/res/values-tl/strings_tv.xml
+++ b/packages/SystemUI/res/values-tl/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Sa pamamagitan ng <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Mga Notification"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Walang Notification"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Nagre-record ang Mikropono"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Nagre-record ang Camera"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Nagre-record ang Camera at Mikropono"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Huminto sa pag-record ang Mikropono"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Huminto sa pag-record ang Camera"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Huminto sa pag-record ang Camera at Mikropono"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings_tv.xml b/packages/SystemUI/res/values-tr/strings_tv.xml
index 28b2d77..54f24c3 100644
--- a/packages/SystemUI/res/values-tr/strings_tv.xml
+++ b/packages/SystemUI/res/values-tr/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> üzerinden"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Bildirimler"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Bildirim Yok"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon kaydediyor"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera kaydediyor"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera ve Mikrofon kaydediyor"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofon kaydı durdu"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera kaydı durdu"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera ve Mikrofon kaydı durdu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings_tv.xml b/packages/SystemUI/res/values-uk/strings_tv.xml
index c86cf31..2ec6d9a 100644
--- a/packages/SystemUI/res/values-uk/strings_tv.xml
+++ b/packages/SystemUI/res/values-uk/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Через <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Сповіщення"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Немає сповіщень"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Мікрофон записує"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Камера записує"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Камера й мікрофон записують"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Мікрофон припинив запис"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Камера припинила запис"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Камера й мікрофон припинили запис"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings_tv.xml b/packages/SystemUI/res/values-ur/strings_tv.xml
index 5810482..566b33f 100644
--- a/packages/SystemUI/res/values-ur/strings_tv.xml
+++ b/packages/SystemUI/res/values-ur/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"بذریعہ <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"اطلاعات"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"کوئی اطلاع نہیں ہے"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"مائیکروفون ریکارڈ کر رہا ہے"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"کیمرا ریکارڈ کر رہا ہے"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"کیمرا اور مائیکروفون ریکارڈ کر رہا ہے"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"مائیکروفون نے ریکارڈ کرنا بند کر دیا"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"کیمرے نے ریکارڈ کرنا بند کر دیا"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"کیمرے اور مائیکروفون نے ریکارڈ کرنا بند کر دیا"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings_tv.xml b/packages/SystemUI/res/values-vi/strings_tv.xml
index 21f5471..0144884 100644
--- a/packages/SystemUI/res/values-vi/strings_tv.xml
+++ b/packages/SystemUI/res/values-vi/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Thông qua <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Thông báo"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Không có thông báo"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Micrô đang ghi"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Máy ảnh đang ghi"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Máy ảnh và micrô đang ghi"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Micrô đã dừng ghi"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Máy ảnh đã dừng ghi"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Máy ảnh và micrô đã dừng ghi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings_tv.xml b/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
index ca814a3..ed914c9 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"通过“<xliff:g id="VPN_APP">%1$s</xliff:g>”"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"通知"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"没有通知"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"麦克风正在录制"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"相机正在录制"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"相机和麦克风正在录制"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"麦克风已停止录制"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"相机已停止录制"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"相机和麦克风已停止录制"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings_tv.xml b/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
index f992b62..dfc34e5 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"透過 <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"通知"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"沒有通知"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"麥克風正在錄音"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"相機正在錄影"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"相機和麥克風正在錄影及錄音"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"麥克風已停止錄音"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"相機已停止錄影"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"相機和麥克風已停止錄影及錄音"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings_tv.xml b/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
index 94135d2..869ac48 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"透過「<xliff:g id="VPN_APP">%1$s</xliff:g>」"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"通知"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"沒有通知"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"麥克風正在錄音"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"相機正在錄影"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"相機和麥克風正在錄影及錄音"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"麥克風已停止錄音"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"相機已停止錄影"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"相機和麥克風已停止錄影及錄音"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings_tv.xml b/packages/SystemUI/res/values-zu/strings_tv.xml
index 79a6575..a3e5255 100644
--- a/packages/SystemUI/res/values-zu/strings_tv.xml
+++ b/packages/SystemUI/res/values-zu/strings_tv.xml
@@ -26,16 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Nge-<xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Izaziso"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Azikho Izaziso"</string>
- <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
- <skip />
- <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
- <skip />
- <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
- <skip />
- <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
- <skip />
- <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
- <skip />
- <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
- <skip />
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Imakrofoni iyarekhoda"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Ikhamera iyarekhoda"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Ikhamera nemakrofoni kuyarekhoda"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Imakrofoni iyekile ukurekhoda"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Ikhamera iyeke ukurekhoda"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Ikhemera nemakrofoni kuyekile ukurekhoda"</string>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 5fec796..2ee0026 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -916,8 +916,8 @@
<dimen name="keyguard_affordance_height">48dp</dimen>
<dimen name="keyguard_affordance_width">48dp</dimen>
- <dimen name="keyguard_affordance_wallet_height">48dp</dimen>
- <dimen name="keyguard_affordance_wallet_width">48dp</dimen>
+ <dimen name="keyguard_affordance_fixed_height">48dp</dimen>
+ <dimen name="keyguard_affordance_fixed_width">48dp</dimen>
<dimen name="keyguard_affordance_horizontal_offset">32dp</dimen>
<dimen name="keyguard_affordance_vertical_offset">32dp</dimen>
@@ -931,6 +931,7 @@
<dimen name="keyguard_lock_padding">20dp</dimen>
<dimen name="keyguard_indication_margin_bottom">32dp</dimen>
+ <dimen name="lock_icon_margin_bottom">98dp</dimen>
<!-- The text size for battery level -->
<dimen name="battery_level_text_size">12sp</dimen>
@@ -1275,6 +1276,8 @@
<!-- Three privacy items. This value must not be exceeded -->
<dimen name="ongoing_appops_chip_max_width">76dp</dimen>
<dimen name="ongoing_appops_dot_diameter">6dp</dimen>
+ <!-- Total minimum padding to enforce to ensure that the dot can always show -->
+ <dimen name="ongoing_appops_dot_min_padding">20dp</dimen>
<dimen name="ongoing_appops_dialog_side_margins">@dimen/notification_shade_content_margin_horizontal</dimen>
@@ -1462,7 +1465,7 @@
<dimen name="lockscreen_shade_notification_movement">24dp</dimen>
<!-- Maximum overshoot for the pulse expansion -->
- <dimen name="pulse_expansion_max_top_overshoot">16dp</dimen>
+ <dimen name="pulse_expansion_max_top_overshoot">32dp</dimen>
<dimen name="people_space_widget_radius">28dp</dimen>
<dimen name="people_space_image_radius">20dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 82d6302..62688ca 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1064,6 +1064,9 @@
<!-- Message shown when lock screen is tapped or face authentication fails. [CHAR LIMIT=60] -->
<string name="keyguard_unlock">Swipe up to open</string>
+ <!-- Message shown when lock screen is tapped or face authentication fails. Provides extra instructions for how the user can enter their device (unlock or proceed to home) [CHAR LIMIT=60] -->
+ <string name="keyguard_unlock_press">Press to open</string>
+
<!-- Message shown when face authentication fails and the pin pad is visible. [CHAR LIMIT=60] -->
<string name="keyguard_retry">Swipe up to try again</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 70ed817..51eabf6 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -764,6 +764,8 @@
<item name="android:windowBackground">@android:color/black</item>
<item name="android:windowAnimationStyle">@null</item>
<item name="android:statusBarColor">@android:color/black</item>
+ <!-- Setting a placeholder will avoid using the SystemUI icon on the splash screen -->
+ <item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_blank</item>
<item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item>
</style>
@@ -898,5 +900,7 @@
<style name="Wallet.Theme" parent="@android:style/Theme.DeviceDefault">
<item name="android:colorBackground">@android:color/system_neutral1_900</item>
<item name="android:itemBackground">@android:color/system_neutral1_800</item>
+ <!-- Setting a placeholder will avoid using the SystemUI icon on the splash screen. -->
+ <item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_blank</item>
</style>
</resources>
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index b2ae2a0..3a23094 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -47,6 +47,7 @@
static_libs: [
"PluginCoreLib",
+ "androidx.dynamicanimation_dynamicanimation",
],
java_version: "1.8",
min_sdk_version: "26",
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index 7f2d252..2519284 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -131,12 +131,13 @@
t.setLayer(leashMap.get(change.getLeash()),
info.getChanges().size() * 3 - i);
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
- if (taskInfo != null) {
- pausingTask = change.getTaskInfo().token;
+ if (taskInfo == null) {
+ continue;
}
+ pausingTask = taskInfo.token;
if (taskInfo.pictureInPictureParams != null
&& taskInfo.pictureInPictureParams.isAutoEnterEnabled()) {
- pipTask = change.getTaskInfo().token;
+ pipTask = taskInfo.token;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java b/packages/SystemUI/shared/src/com/android/systemui/statusbar/policy/CallbackController.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java
rename to packages/SystemUI/shared/src/com/android/systemui/statusbar/policy/CallbackController.java
diff --git a/packages/SystemUI/shared/src/com/android/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/shared/src/com/android/unfold/UnfoldTransitionFactory.kt
new file mode 100644
index 0000000..7594f50
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/UnfoldTransitionFactory.kt
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+@file:JvmName("UnfoldTransitionFactory")
+
+package com.android.unfold
+
+import android.content.Context
+import android.hardware.SensorManager
+import android.hardware.devicestate.DeviceStateManager
+import android.os.Handler
+import com.android.unfold.updates.screen.ScreenStatusProvider
+import com.android.unfold.config.ANIMATION_MODE_HINGE_ANGLE
+import com.android.unfold.config.ResourceUnfoldTransitionConfig
+import com.android.unfold.config.UnfoldTransitionConfig
+import com.android.unfold.progress.FixedTimingTransitionProgressProvider
+import com.android.unfold.progress.PhysicsBasedUnfoldTransitionProgressProvider
+import com.android.unfold.updates.DeviceFoldStateProvider
+import com.android.unfold.updates.hinge.EmptyHingeAngleProvider
+import com.android.unfold.updates.hinge.RotationSensorHingeAngleProvider
+import java.lang.IllegalStateException
+import java.util.concurrent.Executor
+
+fun createUnfoldTransitionProgressProvider(
+ context: Context,
+ config: UnfoldTransitionConfig,
+ screenStatusProvider: ScreenStatusProvider,
+ deviceStateManager: DeviceStateManager,
+ sensorManager: SensorManager,
+ mainHandler: Handler,
+ mainExecutor: Executor
+): UnfoldTransitionProgressProvider {
+
+ if (!config.isEnabled) {
+ throw IllegalStateException("Trying to create " +
+ "UnfoldTransitionProgressProvider when the transition is disabled")
+ }
+
+ val hingeAngleProvider =
+ if (config.mode == ANIMATION_MODE_HINGE_ANGLE) {
+ RotationSensorHingeAngleProvider(sensorManager)
+ } else {
+ EmptyHingeAngleProvider()
+ }
+
+ val foldStateProvider = DeviceFoldStateProvider(
+ context,
+ hingeAngleProvider,
+ screenStatusProvider,
+ deviceStateManager,
+ mainExecutor
+ )
+
+ return if (config.mode == ANIMATION_MODE_HINGE_ANGLE) {
+ PhysicsBasedUnfoldTransitionProgressProvider(
+ mainHandler,
+ foldStateProvider
+ )
+ } else {
+ FixedTimingTransitionProgressProvider(foldStateProvider)
+ }
+}
+
+fun createConfig(context: Context): UnfoldTransitionConfig =
+ ResourceUnfoldTransitionConfig(context)
diff --git a/packages/SystemUI/shared/src/com/android/unfold/UnfoldTransitionProgressProvider.kt b/packages/SystemUI/shared/src/com/android/unfold/UnfoldTransitionProgressProvider.kt
new file mode 100644
index 0000000..2ddb49c
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/UnfoldTransitionProgressProvider.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.unfold
+
+import android.annotation.FloatRange
+import com.android.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.systemui.statusbar.policy.CallbackController
+
+/**
+ * Interface that allows to receive unfold transition progress updates.
+ * It can be used to update view properties based on the current animation progress.
+ * onTransitionProgress callback could be called on each frame.
+ *
+ * Use [createUnfoldTransitionProgressProvider] to create instances of this interface
+ */
+interface UnfoldTransitionProgressProvider : CallbackController<TransitionProgressListener> {
+
+ fun destroy()
+
+ interface TransitionProgressListener {
+ fun onTransitionStarted()
+ fun onTransitionFinished()
+ fun onTransitionProgress(@FloatRange(from = 0.0, to = 1.0) progress: Float)
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/unfold/config/ResourceUnfoldTransitionConfig.kt b/packages/SystemUI/shared/src/com/android/unfold/config/ResourceUnfoldTransitionConfig.kt
new file mode 100644
index 0000000..bde87a5
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/config/ResourceUnfoldTransitionConfig.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.unfold.config
+
+import android.content.Context
+import android.os.SystemProperties
+
+internal class ResourceUnfoldTransitionConfig(
+ private val context: Context
+) : UnfoldTransitionConfig {
+
+ override val isEnabled: Boolean
+ get() = readIsEnabled() && mode != ANIMATION_MODE_DISABLED
+
+ @AnimationMode
+ override val mode: Int
+ get() = SystemProperties.getInt(UNFOLD_TRANSITION_MODE_PROPERTY_NAME,
+ ANIMATION_MODE_FIXED_TIMING)
+
+ private fun readIsEnabled(): Boolean = context.resources
+ .getBoolean(com.android.internal.R.bool.config_unfoldTransitionEnabled)
+}
+
+/**
+ * Temporary persistent property to control unfold transition mode
+ * See [com.android.unfold.config.AnimationMode]
+ */
+private const val UNFOLD_TRANSITION_MODE_PROPERTY_NAME = "persist.unfold.transition_mode"
diff --git a/packages/SystemUI/shared/src/com/android/unfold/config/UnfoldTransitionConfig.kt b/packages/SystemUI/shared/src/com/android/unfold/config/UnfoldTransitionConfig.kt
new file mode 100644
index 0000000..f000c69
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/config/UnfoldTransitionConfig.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.unfold.config
+
+import android.annotation.IntDef
+
+interface UnfoldTransitionConfig {
+ val isEnabled: Boolean
+
+ @AnimationMode
+ val mode: Int
+}
+
+@IntDef(prefix = ["ANIMATION_MODE_"], value = [
+ ANIMATION_MODE_DISABLED,
+ ANIMATION_MODE_FIXED_TIMING,
+ ANIMATION_MODE_HINGE_ANGLE
+])
+
+@Retention(AnnotationRetention.SOURCE)
+annotation class AnimationMode
+
+const val ANIMATION_MODE_DISABLED = 0
+const val ANIMATION_MODE_FIXED_TIMING = 1
+const val ANIMATION_MODE_HINGE_ANGLE = 2
diff --git a/packages/SystemUI/shared/src/com/android/unfold/progress/FixedTimingTransitionProgressProvider.kt b/packages/SystemUI/shared/src/com/android/unfold/progress/FixedTimingTransitionProgressProvider.kt
new file mode 100644
index 0000000..acfe073
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/progress/FixedTimingTransitionProgressProvider.kt
@@ -0,0 +1,117 @@
+/*
+ * 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.unfold.progress
+
+import android.animation.Animator
+import android.animation.ObjectAnimator
+import android.util.FloatProperty
+import com.android.unfold.UnfoldTransitionProgressProvider
+import com.android.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
+import com.android.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE
+import com.android.unfold.updates.FoldStateProvider
+import com.android.unfold.updates.FoldStateProvider.FoldUpdate
+
+/**
+ * Emits animation progress with fixed timing after unfolding
+ */
+internal class FixedTimingTransitionProgressProvider(
+ private val foldStateProvider: FoldStateProvider
+) : UnfoldTransitionProgressProvider, FoldStateProvider.FoldUpdatesListener {
+
+ private val animatorListener = AnimatorListener()
+ private val animator =
+ ObjectAnimator.ofFloat(this, AnimationProgressProperty, 0f, 1f)
+ .apply {
+ duration = TRANSITION_TIME_MILLIS
+ addListener(animatorListener)
+ }
+
+
+ private var transitionProgress: Float = 0.0f
+ set(value) {
+ listeners.forEach { it.onTransitionProgress(value) }
+ field = value
+ }
+
+ private val listeners: MutableList<TransitionProgressListener> = mutableListOf()
+
+ init {
+ foldStateProvider.addCallback(this)
+ foldStateProvider.start()
+ }
+
+ override fun destroy() {
+ animator.cancel()
+ foldStateProvider.removeCallback(this)
+ foldStateProvider.stop()
+ }
+
+ override fun onFoldUpdate(@FoldUpdate update: Int) {
+ when (update) {
+ FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE ->
+ animator.start()
+ FOLD_UPDATE_FINISH_CLOSED ->
+ animator.cancel()
+ }
+ }
+
+ override fun addCallback(listener: TransitionProgressListener) {
+ listeners.add(listener)
+ }
+
+ override fun removeCallback(listener: TransitionProgressListener) {
+ listeners.remove(listener)
+ }
+
+ override fun onHingeAngleUpdate(angle: Float) {
+ }
+
+ private object AnimationProgressProperty :
+ FloatProperty<FixedTimingTransitionProgressProvider>("animation_progress") {
+
+ override fun setValue(
+ provider: FixedTimingTransitionProgressProvider,
+ value: Float
+ ) {
+ provider.transitionProgress = value
+ }
+
+ override fun get(provider: FixedTimingTransitionProgressProvider): Float =
+ provider.transitionProgress
+ }
+
+ private inner class AnimatorListener : Animator.AnimatorListener {
+
+ override fun onAnimationStart(animator: Animator) {
+ listeners.forEach { it.onTransitionStarted() }
+ }
+
+ override fun onAnimationEnd(animator: Animator) {
+ listeners.forEach { it.onTransitionFinished() }
+ }
+
+ override fun onAnimationRepeat(animator: Animator) {
+ }
+
+ override fun onAnimationCancel(animator: Animator) {
+ }
+ }
+
+ private companion object {
+ private const val TRANSITION_TIME_MILLIS = 400L
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/shared/src/com/android/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
new file mode 100644
index 0000000..d9d037f
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
@@ -0,0 +1,184 @@
+/*
+ * 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.unfold.progress
+
+import android.os.Handler
+import androidx.dynamicanimation.animation.DynamicAnimation
+import androidx.dynamicanimation.animation.FloatPropertyCompat
+import androidx.dynamicanimation.animation.SpringAnimation
+import androidx.dynamicanimation.animation.SpringForce
+import com.android.unfold.UnfoldTransitionProgressProvider
+import com.android.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
+import com.android.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN
+import com.android.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE
+import com.android.unfold.updates.FoldStateProvider
+import com.android.unfold.updates.FoldStateProvider.FoldUpdate
+import com.android.unfold.updates.FoldStateProvider.FoldUpdatesListener
+
+/**
+ * Maps fold updates to unfold transition progress using DynamicAnimation.
+ *
+ * TODO(b/193793338) Current limitations:
+ * - doesn't handle folding transition
+ * - doesn't handle postures
+ */
+internal class PhysicsBasedUnfoldTransitionProgressProvider(
+ private val handler: Handler,
+ private val foldStateProvider: FoldStateProvider
+) :
+ UnfoldTransitionProgressProvider,
+ FoldUpdatesListener,
+ DynamicAnimation.OnAnimationEndListener {
+
+ private val springAnimation = SpringAnimation(this, AnimationProgressProperty)
+ .apply {
+ addEndListener(this@PhysicsBasedUnfoldTransitionProgressProvider)
+ }
+
+ private val timeoutRunnable = TimeoutRunnable()
+
+ private var isTransitionRunning = false
+ private var isAnimatedCancelRunning = false
+
+ private var transitionProgress: Float = 0.0f
+ set(value) {
+ if (isTransitionRunning) {
+ listeners.forEach { it.onTransitionProgress(value) }
+ }
+ field = value
+ }
+
+ private val listeners: MutableList<TransitionProgressListener> = mutableListOf()
+
+ init {
+ foldStateProvider.addCallback(this)
+ foldStateProvider.start()
+ }
+
+ override fun destroy() {
+ foldStateProvider.stop()
+ }
+
+ override fun onHingeAngleUpdate(angle: Float) {
+ if (!isTransitionRunning || isAnimatedCancelRunning) return
+ springAnimation.animateToFinalPosition(angle / 180f)
+ }
+
+ override fun onFoldUpdate(@FoldUpdate update: Int) {
+ when (update) {
+ FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE -> {
+ onStartTransition()
+ startTransition(startValue = 0f)
+ }
+ FOLD_UPDATE_FINISH_FULL_OPEN -> {
+ cancelTransition(endValue = 1f, animate = true)
+ }
+ FOLD_UPDATE_FINISH_CLOSED -> {
+ cancelTransition(endValue = 0f, animate = false)
+ }
+ }
+ }
+
+ private fun cancelTransition(endValue: Float, animate: Boolean) {
+ handler.removeCallbacks(timeoutRunnable)
+
+ if (animate) {
+ isAnimatedCancelRunning = true
+ springAnimation.animateToFinalPosition(endValue)
+ } else {
+ transitionProgress = endValue
+ isAnimatedCancelRunning = false
+ isTransitionRunning = false
+ springAnimation.cancel()
+
+ listeners.forEach {
+ it.onTransitionFinished()
+ }
+ }
+ }
+
+ override fun onAnimationEnd(
+ animation: DynamicAnimation<out DynamicAnimation<*>>,
+ canceled: Boolean,
+ value: Float,
+ velocity: Float
+ ) {
+ if (isAnimatedCancelRunning) {
+ cancelTransition(value, animate = false)
+ }
+ }
+
+ private fun onStartTransition() {
+ listeners.forEach {
+ it.onTransitionStarted()
+ }
+ isTransitionRunning = true
+ }
+
+ private fun startTransition(startValue: Float) {
+ if (!isTransitionRunning) onStartTransition()
+
+ springAnimation.apply {
+ spring = SpringForce().apply {
+ finalPosition = startValue
+ dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY
+ stiffness = SPRING_STIFFNESS
+ }
+ minimumVisibleChange = MINIMAL_VISIBLE_CHANGE
+ setStartValue(startValue)
+ setMinValue(0f)
+ setMaxValue(1f)
+ }
+
+ springAnimation.start()
+
+ handler.postDelayed(timeoutRunnable, TRANSITION_TIMEOUT_MILLIS)
+ }
+
+ override fun addCallback(listener: TransitionProgressListener) {
+ listeners.add(listener)
+ }
+
+ override fun removeCallback(listener: TransitionProgressListener) {
+ listeners.remove(listener)
+ }
+
+ private inner class TimeoutRunnable : Runnable {
+
+ override fun run() {
+ cancelTransition(endValue = 1f, animate = true)
+ }
+ }
+
+ private object AnimationProgressProperty :
+ FloatPropertyCompat<PhysicsBasedUnfoldTransitionProgressProvider>("animation_progress") {
+
+ override fun setValue(
+ provider: PhysicsBasedUnfoldTransitionProgressProvider,
+ value: Float
+ ) {
+ provider.transitionProgress = value
+ }
+
+ override fun getValue(provider: PhysicsBasedUnfoldTransitionProgressProvider): Float =
+ provider.transitionProgress
+ }
+}
+
+private const val TRANSITION_TIMEOUT_MILLIS = 2000L
+private const val SPRING_STIFFNESS = 200.0f
+private const val MINIMAL_VISIBLE_CHANGE = 0.001f
diff --git a/packages/SystemUI/shared/src/com/android/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/shared/src/com/android/unfold/updates/DeviceFoldStateProvider.kt
new file mode 100644
index 0000000..3a21b80
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/updates/DeviceFoldStateProvider.kt
@@ -0,0 +1,124 @@
+/*
+ * 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.unfold.updates
+
+import android.content.Context
+import android.hardware.devicestate.DeviceStateManager
+import androidx.core.util.Consumer
+import com.android.unfold.updates.screen.ScreenStatusProvider
+import com.android.unfold.updates.FoldStateProvider.FoldUpdate
+import com.android.unfold.updates.FoldStateProvider.FoldUpdatesListener
+import com.android.unfold.updates.hinge.FULLY_OPEN_DEGREES
+import com.android.unfold.updates.hinge.HingeAngleProvider
+import java.util.concurrent.Executor
+
+internal class DeviceFoldStateProvider(
+ context: Context,
+ private val hingeAngleProvider: HingeAngleProvider,
+ private val screenStatusProvider: ScreenStatusProvider,
+ private val deviceStateManager: DeviceStateManager,
+ private val mainExecutor: Executor
+) : FoldStateProvider {
+
+ private val outputListeners: MutableList<FoldUpdatesListener> = mutableListOf()
+
+ @FoldUpdate
+ private var lastFoldUpdate: Int? = null
+
+ private val hingeAngleListener = HingeAngleListener()
+ private val screenListener = ScreenStatusListener()
+ private val foldStateListener = FoldStateListener(context)
+
+ private var isFolded = false
+
+ override fun start() {
+ deviceStateManager.registerCallback(
+ mainExecutor,
+ foldStateListener
+ )
+ screenStatusProvider.addCallback(screenListener)
+ hingeAngleProvider.addCallback(hingeAngleListener)
+ }
+
+ override fun stop() {
+ screenStatusProvider.removeCallback(screenListener)
+ deviceStateManager.unregisterCallback(foldStateListener)
+ hingeAngleProvider.removeCallback(hingeAngleListener)
+ hingeAngleProvider.stop()
+ }
+
+ override fun addCallback(listener: FoldUpdatesListener) {
+ outputListeners.add(listener)
+ }
+
+ override fun removeCallback(listener: FoldUpdatesListener) {
+ outputListeners.remove(listener)
+ }
+
+ private fun onHingeAngle(angle: Float) {
+ when (lastFoldUpdate) {
+ FOLD_UPDATE_FINISH_FULL_OPEN -> {
+ if (FULLY_OPEN_DEGREES - angle > MOVEMENT_THRESHOLD_DEGREES) {
+ lastFoldUpdate = FOLD_UPDATE_START_CLOSING
+ outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_START_CLOSING) }
+ }
+ }
+ FOLD_UPDATE_START_OPENING, FOLD_UPDATE_START_CLOSING -> {
+ if (FULLY_OPEN_DEGREES - angle < FULLY_OPEN_THRESHOLD_DEGREES) {
+ lastFoldUpdate = FOLD_UPDATE_FINISH_FULL_OPEN
+ outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) }
+ }
+ }
+ }
+
+ outputListeners.forEach { it.onHingeAngleUpdate(angle) }
+ }
+
+ private inner class FoldStateListener(context: Context) :
+ DeviceStateManager.FoldStateListener(context, { folded: Boolean ->
+ isFolded = folded
+
+ if (folded) {
+ lastFoldUpdate = FOLD_UPDATE_FINISH_CLOSED
+ outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_FINISH_CLOSED) }
+ hingeAngleProvider.stop()
+ } else {
+ lastFoldUpdate = FOLD_UPDATE_START_OPENING
+ outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_START_OPENING) }
+ hingeAngleProvider.start()
+ }
+ })
+
+ private inner class ScreenStatusListener :
+ ScreenStatusProvider.ScreenListener {
+
+ override fun onScreenTurnedOn() {
+ if (!isFolded) {
+ outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) }
+ }
+ }
+ }
+
+ private inner class HingeAngleListener : Consumer<Float> {
+
+ override fun accept(angle: Float) {
+ onHingeAngle(angle)
+ }
+ }
+}
+
+private const val MOVEMENT_THRESHOLD_DEGREES = 10f
+private const val FULLY_OPEN_THRESHOLD_DEGREES = 10f
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/unfold/updates/FoldStateProvider.kt b/packages/SystemUI/shared/src/com/android/unfold/updates/FoldStateProvider.kt
new file mode 100644
index 0000000..2c3a6ec
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/updates/FoldStateProvider.kt
@@ -0,0 +1,55 @@
+/*
+ * 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.unfold.updates
+
+import android.annotation.FloatRange
+import android.annotation.IntDef
+import com.android.unfold.updates.FoldStateProvider.FoldUpdatesListener
+import com.android.systemui.statusbar.policy.CallbackController
+
+/**
+ * Allows to subscribe to main events related to fold/unfold process such as hinge angle update,
+ * start folding/unfolding, screen availability
+ */
+internal interface FoldStateProvider : CallbackController<FoldUpdatesListener> {
+ fun start()
+ fun stop()
+
+ interface FoldUpdatesListener {
+ fun onHingeAngleUpdate(@FloatRange(from = 0.0, to = 180.0) angle: Float)
+ fun onFoldUpdate(@FoldUpdate update: Int)
+ }
+
+ @IntDef(prefix = ["FOLD_UPDATE_"], value = [
+ FOLD_UPDATE_START_OPENING,
+ FOLD_UPDATE_HALF_OPEN,
+ FOLD_UPDATE_START_CLOSING,
+ FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE,
+ FOLD_UPDATE_FINISH_HALF_OPEN,
+ FOLD_UPDATE_FINISH_FULL_OPEN,
+ FOLD_UPDATE_FINISH_CLOSED
+ ])
+ @Retention(AnnotationRetention.SOURCE)
+ annotation class FoldUpdate
+}
+
+const val FOLD_UPDATE_START_OPENING = 0
+const val FOLD_UPDATE_HALF_OPEN = 1
+const val FOLD_UPDATE_START_CLOSING = 2
+const val FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE = 3
+const val FOLD_UPDATE_FINISH_HALF_OPEN = 4
+const val FOLD_UPDATE_FINISH_FULL_OPEN = 5
+const val FOLD_UPDATE_FINISH_CLOSED = 6
diff --git a/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/EmptyHingeAngleProvider.kt b/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/EmptyHingeAngleProvider.kt
new file mode 100644
index 0000000..905b086
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/EmptyHingeAngleProvider.kt
@@ -0,0 +1,17 @@
+package com.android.unfold.updates.hinge
+
+import androidx.core.util.Consumer
+
+internal class EmptyHingeAngleProvider : HingeAngleProvider {
+ override fun start() {
+ }
+
+ override fun stop() {
+ }
+
+ override fun removeCallback(listener: Consumer<Float>) {
+ }
+
+ override fun addCallback(listener: Consumer<Float>) {
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/HingeAngleProvider.kt b/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/HingeAngleProvider.kt
new file mode 100644
index 0000000..4196f60
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/HingeAngleProvider.kt
@@ -0,0 +1,12 @@
+package com.android.unfold.updates.hinge
+
+import androidx.core.util.Consumer
+import com.android.systemui.statusbar.policy.CallbackController
+
+internal interface HingeAngleProvider : CallbackController<Consumer<Float>> {
+ fun start()
+ fun stop()
+}
+
+const val FULLY_OPEN_DEGREES = 180f
+const val FULLY_CLOSED_DEGREES = 0f
diff --git a/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/RotationSensorHingeAngleProvider.kt b/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/RotationSensorHingeAngleProvider.kt
new file mode 100644
index 0000000..011582e
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/RotationSensorHingeAngleProvider.kt
@@ -0,0 +1,67 @@
+package com.android.unfold.updates.hinge
+
+import android.hardware.Sensor
+import android.hardware.SensorEvent
+import android.hardware.SensorEventListener
+import android.hardware.SensorManager
+import androidx.core.util.Consumer
+import com.android.systemui.shared.recents.utilities.Utilities
+
+/**
+ * Temporary hinge angle provider that uses rotation sensor instead.
+ * It requires to have the device in a certain position to work correctly
+ * (flat to the ground)
+ */
+internal class RotationSensorHingeAngleProvider(
+ private val sensorManager: SensorManager
+) : HingeAngleProvider {
+
+ private val sensorListener = HingeAngleSensorListener()
+ private val listeners: MutableList<Consumer<Float>> = arrayListOf()
+
+ override fun start() {
+ val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR)
+ sensorManager.registerListener(sensorListener, sensor, SensorManager.SENSOR_DELAY_FASTEST)
+ }
+
+ override fun stop() {
+ sensorManager.unregisterListener(sensorListener)
+ }
+
+ override fun removeCallback(listener: Consumer<Float>) {
+ listeners.remove(listener)
+ }
+
+ override fun addCallback(listener: Consumer<Float>) {
+ listeners.add(listener)
+ }
+
+ private fun onHingeAngle(angle: Float) {
+ listeners.forEach { it.accept(angle) }
+ }
+
+ private inner class HingeAngleSensorListener : SensorEventListener {
+
+ override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
+ }
+
+ override fun onSensorChanged(event: SensorEvent) {
+ // Jumbojack sends incorrect sensor reading 1.0f event in the beginning, let's ignore it
+ if (event.values[3] == 1.0f) return
+
+ val angleRadians = event.values.convertToAngle()
+ val hingeAngleDegrees = Math.toDegrees(angleRadians).toFloat()
+ val angle = Utilities.clamp(hingeAngleDegrees, FULLY_CLOSED_DEGREES, FULLY_OPEN_DEGREES)
+ onHingeAngle(angle)
+ }
+
+ private val rotationMatrix = FloatArray(9)
+ private val resultOrientation = FloatArray(9)
+
+ private fun FloatArray.convertToAngle(): Double {
+ SensorManager.getRotationMatrixFromVector(rotationMatrix, this)
+ SensorManager.getOrientation(rotationMatrix, resultOrientation)
+ return resultOrientation[2] + Math.PI
+ }
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/unfold/updates/screen/ScreenStatusProvider.kt b/packages/SystemUI/shared/src/com/android/unfold/updates/screen/ScreenStatusProvider.kt
new file mode 100644
index 0000000..a65e888
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/updates/screen/ScreenStatusProvider.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.unfold.updates.screen
+
+import com.android.unfold.updates.screen.ScreenStatusProvider.ScreenListener
+import com.android.systemui.statusbar.policy.CallbackController
+
+interface ScreenStatusProvider : CallbackController<ScreenListener> {
+
+ interface ScreenListener {
+ /**
+ * Called when the screen is on and ready (windows are drawn and screen blocker is removed)
+ */
+ fun onScreenTurnedOn()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 8fc4240..82ade7a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -22,15 +22,14 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
-import android.widget.LinearLayout;
+
+import androidx.constraintlayout.widget.ConstraintLayout;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.settingslib.animation.DisappearAnimationUtils;
import com.android.systemui.R;
-import java.util.List;
-
/**
* Displays a PIN pad for unlocking.
*/
@@ -40,10 +39,6 @@
private final DisappearAnimationUtils mDisappearAnimationUtils;
private final DisappearAnimationUtils mDisappearAnimationUtilsLocked;
private ViewGroup mContainer;
- private ViewGroup mRow0;
- private ViewGroup mRow1;
- private ViewGroup mRow2;
- private ViewGroup mRow3;
private int mDisappearYTranslation;
private View[][] mViews;
@@ -82,30 +77,38 @@
}
private void updateMargins() {
+ // Re-apply everything to the keys...
int bottomMargin = mContext.getResources().getDimensionPixelSize(
- R.dimen.num_pad_row_margin_bottom);
-
- for (ViewGroup vg : List.of(mRow1, mRow2, mRow3)) {
- ((LinearLayout.LayoutParams) vg.getLayoutParams()).setMargins(0, 0, 0, bottomMargin);
- }
-
- bottomMargin = mContext.getResources().getDimensionPixelSize(
R.dimen.num_pad_entry_row_margin_bottom);
- ((LinearLayout.LayoutParams) mRow0.getLayoutParams()).setMargins(0, 0, 0, bottomMargin);
+ int rightMargin = mContext.getResources().getDimensionPixelSize(
+ R.dimen.num_pad_key_margin_end);
+ String ratio = mContext.getResources().getString(R.string.num_pad_key_ratio);
- if (mEcaView != null) {
- int ecaTopMargin = mContext.getResources().getDimensionPixelSize(
- R.dimen.keyguard_eca_top_margin);
- int ecaBottomMargin = mContext.getResources().getDimensionPixelSize(
- R.dimen.keyguard_eca_bottom_margin);
- ((LinearLayout.LayoutParams) mEcaView.getLayoutParams()).setMargins(0, ecaTopMargin,
- 0, ecaBottomMargin);
+ // mView contains all Views that make up the PIN pad; row0 = the entry test field, then
+ // rows 1-4 contain the buttons. Iterate over all views that make up the buttons in the pad,
+ // and re-set all the margins.
+ for (int row = 1; row < 5; row++) {
+ for (int column = 0; column < 3; column++) {
+ View key = mViews[row][column];
+
+ ConstraintLayout.LayoutParams lp =
+ (ConstraintLayout.LayoutParams) key.getLayoutParams();
+
+ lp.dimensionRatio = ratio;
+
+ // Don't set any margins on the last row of buttons.
+ if (row != 4) {
+ lp.bottomMargin = bottomMargin;
+ }
+
+ // Don't set margins on the rightmost buttons.
+ if (column != 2) {
+ lp.rightMargin = rightMargin;
+ }
+
+ key.setLayoutParams(lp);
+ }
}
-
- View entryView = findViewById(R.id.pinEntry);
- ViewGroup.LayoutParams lp = entryView.getLayoutParams();
- lp.height = mContext.getResources().getDimensionPixelSize(R.dimen.keyguard_password_height);
- entryView.setLayoutParams(lp);
}
@Override
@@ -113,13 +116,9 @@
super.onFinishInflate();
mContainer = findViewById(R.id.pin_container);
- mRow0 = findViewById(R.id.row0);
- mRow1 = findViewById(R.id.row1);
- mRow2 = findViewById(R.id.row2);
- mRow3 = findViewById(R.id.row3);
mViews = new View[][]{
new View[]{
- mRow0, null, null
+ findViewById(R.id.row0), null, null
},
new View[]{
findViewById(R.id.key1), findViewById(R.id.key2),
@@ -188,9 +187,6 @@
private void enableClipping(boolean enable) {
mContainer.setClipToPadding(enable);
mContainer.setClipChildren(enable);
- mRow1.setClipToPadding(enable);
- mRow2.setClipToPadding(enable);
- mRow3.setClipToPadding(enable);
setClipChildren(enable);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 0e25fac..5ef7143 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -2068,6 +2068,15 @@
}
/**
+ * @return if udfps is available on this device. will return true even if the user hasn't
+ * enrolled udfps.
+ */
+ public boolean isUdfpsAvailable() {
+ return mAuthController.getUdfpsProps() != null
+ && !mAuthController.getUdfpsProps().isEmpty();
+ }
+
+ /**
* @return true if there's at least one face enrolled
*/
public boolean isFaceEnrolled() {
@@ -2398,8 +2407,10 @@
if (isEncryptedOrLockdown(userId) && supportsFaceDetection) {
mFaceManager.detectFace(mFaceCancelSignal, mFaceDetectionCallback, userId);
} else {
+ final boolean isBypassEnabled = mKeyguardBypassController != null
+ && mKeyguardBypassController.isBypassEnabled();
mFaceManager.authenticate(null /* crypto */, mFaceCancelSignal,
- mFaceAuthenticationCallback, null /* handler */, userId);
+ mFaceAuthenticationCallback, null /* handler */, userId, isBypassEnabled);
}
setFaceRunningState(BIOMETRIC_STATE_RUNNING);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 8b974b4..9c8582fa 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -72,7 +72,10 @@
*/
@StatusBarComponent.StatusBarScope
public class LockIconViewController extends ViewController<LockIconView> implements Dumpable {
-
+ private static final float sDefaultDensity =
+ (float) DisplayMetrics.DENSITY_DEVICE_STABLE / (float) DisplayMetrics.DENSITY_DEFAULT;
+ private static final int sLockIconRadiusPx = (int) (sDefaultDensity * 36);
+ private static final float sDistAboveKgBottomAreaPx = sDefaultDensity * 12;
private static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES =
new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
@@ -111,9 +114,7 @@
private boolean mHasUdfps;
private float mHeightPixels;
private float mWidthPixels;
- private float mDensity;
- private int mAmbientIndicationHeight; // in pixels
- private int mKgIndicationHeight; // in pixels
+ private int mBottomPadding; // in pixels
private boolean mShowUnlockIcon;
private boolean mShowLockIcon;
@@ -318,11 +319,8 @@
final DisplayMetrics metrics = mView.getContext().getResources().getDisplayMetrics();
mWidthPixels = metrics.widthPixels;
mHeightPixels = metrics.heightPixels;
- mDensity = metrics.density;
- mKgIndicationHeight = mView.getContext().getResources().getDimensionPixelSize(
- R.dimen.keyguard_indication_margin_bottom)
- + mView.getContext().getResources().getDimensionPixelSize(
- R.dimen.keyguard_indication_bottom_padding);
+ mBottomPadding = mView.getContext().getResources().getDimensionPixelSize(
+ R.dimen.lock_icon_margin_bottom);
updateLockIconLocation();
}
@@ -332,26 +330,15 @@
mView.setCenterLocation(new PointF(props.sensorLocationX, props.sensorLocationY),
props.sensorRadius);
} else {
- final float distAboveKgBottomArea = 12 * mDensity;
- final float radius = 36 * mDensity;
- final int kgBottomAreaHeight = Math.max(mKgIndicationHeight, mAmbientIndicationHeight);
mView.setCenterLocation(
new PointF(mWidthPixels / 2,
- mHeightPixels - kgBottomAreaHeight - distAboveKgBottomArea
- - radius / 2), (int) radius);
+ mHeightPixels - mBottomPadding - sDistAboveKgBottomAreaPx
+ - sLockIconRadiusPx), sLockIconRadiusPx);
}
mView.getHitRect(mSensorTouchLocation);
}
- /**
- * Set the location of ambient indication if showing (ie: now playing)
- */
- public void setAmbientIndicationBottomPadding(int ambientIndicationBottomPadding) {
- mAmbientIndicationHeight = ambientIndicationBottomPadding;
- updateLockIconLocation();
- }
-
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("mUdfpsEnrolled: " + mUdfpsEnrolled);
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
index 57407f1..99f9558 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
@@ -59,7 +59,9 @@
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// Set width/height to the same value to ensure a smooth circle for the bg, but shrink
- // the height to match the old pin bouncer
+ // the height to match the old pin bouncer.
+ // This is only used for PIN/PUK; the main PIN pad now uses ConstraintLayout, which will
+ // force our width/height to conform to the ratio in the layout.
int width = getMeasuredWidth();
boolean shortenHeight = mAnimator == null
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 232c6fc..e79ea9a 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -175,7 +175,9 @@
measureChildren(widthMeasureSpec, heightMeasureSpec);
// Set width/height to the same value to ensure a smooth circle for the bg, but shrink
- // the height to match the old pin bouncer
+ // the height to match the old pin bouncer.
+ // This is only used for PIN/PUK; the main PIN pad now uses ConstraintLayout, which will
+ // force our width/height to conform to the ratio in the layout.
int width = getMeasuredWidth();
boolean shortenHeight = mAnimator == null
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 5418770..f8c57bf 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -98,6 +98,7 @@
import com.android.systemui.statusbar.phone.ManagedProfileController;
import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper;
import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
import com.android.systemui.statusbar.policy.AccessibilityController;
@@ -358,6 +359,7 @@
@Inject Lazy<EdgeBackGestureHandler.Factory> mEdgeBackGestureHandlerFactoryLazy;
@Inject Lazy<UiEventLogger> mUiEventLogger;
@Inject Lazy<FeatureFlags> mFeatureFlagsLazy;
+ @Inject Lazy<StatusBarContentInsetsProvider> mContentInsetsProviderLazy;
@Inject
public Dependency() {
@@ -572,6 +574,7 @@
mEdgeBackGestureHandlerFactoryLazy::get);
mProviders.put(UiEventLogger.class, mUiEventLogger::get);
mProviders.put(FeatureFlags.class, mFeatureFlagsLazy::get);
+ mProviders.put(StatusBarContentInsetsProvider.class, mContentInsetsProviderLazy::get);
Dependency.setInstance(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
index 0ae89bc..b5b6b13 100644
--- a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
@@ -16,25 +16,24 @@
package com.android.systemui;
-import android.app.ActivityManager;
-import android.app.Dialog;
+import android.app.AlertDialog;
import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.UserInfo;
-import android.os.RemoteException;
import android.os.UserHandle;
-import android.provider.Settings;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.qs.QSUserSwitcherEvent;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.util.settings.SecureSettings;
/**
* Manages notification when a guest session is resumed.
@@ -43,16 +42,23 @@
private static final String TAG = "GuestResumeSessionReceiver";
- private static final String SETTING_GUEST_HAS_LOGGED_IN = "systemui.guest_has_logged_in";
+ @VisibleForTesting
+ public static final String SETTING_GUEST_HAS_LOGGED_IN = "systemui.guest_has_logged_in";
- private Dialog mNewSessionDialog;
+ @VisibleForTesting
+ public AlertDialog mNewSessionDialog;
+ private final UserTracker mUserTracker;
private final UserSwitcherController mUserSwitcherController;
private final UiEventLogger mUiEventLogger;
+ private final SecureSettings mSecureSettings;
public GuestResumeSessionReceiver(UserSwitcherController userSwitcherController,
- UiEventLogger uiEventLogger) {
+ UserTracker userTracker, UiEventLogger uiEventLogger,
+ SecureSettings secureSettings) {
mUserSwitcherController = userSwitcherController;
+ mUserTracker = userTracker;
mUiEventLogger = uiEventLogger;
+ mSecureSettings = secureSettings;
}
/**
@@ -78,26 +84,19 @@
return;
}
- UserInfo currentUser;
- try {
- currentUser = ActivityManager.getService().getCurrentUser();
- } catch (RemoteException e) {
- return;
- }
+ UserInfo currentUser = mUserTracker.getUserInfo();
if (!currentUser.isGuest()) {
return;
}
- ContentResolver cr = context.getContentResolver();
- int notFirstLogin = Settings.System.getIntForUser(
- cr, SETTING_GUEST_HAS_LOGGED_IN, 0, userId);
+ int notFirstLogin = mSecureSettings.getIntForUser(
+ SETTING_GUEST_HAS_LOGGED_IN, 0, userId);
if (notFirstLogin != 0) {
mNewSessionDialog = new ResetSessionDialog(context, mUserSwitcherController,
mUiEventLogger, userId);
mNewSessionDialog.show();
} else {
- Settings.System.putIntForUser(
- cr, SETTING_GUEST_HAS_LOGGED_IN, 1, userId);
+ mSecureSettings.putIntForUser(SETTING_GUEST_HAS_LOGGED_IN, 1, userId);
}
}
}
@@ -109,18 +108,26 @@
}
}
- private static class ResetSessionDialog extends SystemUIDialog implements
+ /**
+ * Dialog shown when user when asking for confirmation before deleting guest user.
+ */
+ @VisibleForTesting
+ public static class ResetSessionDialog extends SystemUIDialog implements
DialogInterface.OnClickListener {
- private static final int BUTTON_WIPE = BUTTON_NEGATIVE;
- private static final int BUTTON_DONTWIPE = BUTTON_POSITIVE;
+ @VisibleForTesting
+ public static final int BUTTON_WIPE = BUTTON_NEGATIVE;
+ @VisibleForTesting
+ public static final int BUTTON_DONTWIPE = BUTTON_POSITIVE;
private final UserSwitcherController mUserSwitcherController;
private final UiEventLogger mUiEventLogger;
private final int mUserId;
- ResetSessionDialog(Context context, UserSwitcherController userSwitcherController,
- UiEventLogger uiEventLogger, int userId) {
+ ResetSessionDialog(Context context,
+ UserSwitcherController userSwitcherController,
+ UiEventLogger uiEventLogger,
+ int userId) {
super(context);
setTitle(context.getString(R.string.guest_wipe_session_title));
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index e9c5653..f653088 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -797,8 +797,8 @@
}
static boolean shouldDrawCutout(Context context) {
- return context.getResources().getBoolean(
- com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout);
+ return DisplayCutout.getFillBuiltInDisplayCutout(
+ context.getResources(), context.getDisplay().getUniqueId());
}
private void updateLayoutParams() {
@@ -1085,7 +1085,8 @@
int dw = flipped ? lh : lw;
int dh = flipped ? lw : lh;
- Path path = DisplayCutout.pathFromResources(getResources(), dw, dh);
+ Path path = DisplayCutout.pathFromResources(
+ getResources(), getDisplay().getUniqueId(), dw, dh);
if (path != null) {
mBoundingPath.set(path);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonModeObserver.java b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonModeObserver.java
index 9bedb1e..fbb909f 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonModeObserver.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonModeObserver.java
@@ -17,6 +17,7 @@
package com.android.systemui.accessibility;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
import android.annotation.IntDef;
@@ -49,7 +50,8 @@
@Retention(RetentionPolicy.SOURCE)
@IntDef({
ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR,
- ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU
+ ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU,
+ ACCESSIBILITY_BUTTON_MODE_GESTURE
})
public @interface AccessibilityButtonMode {}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
index c241c08..4104e31 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
@@ -64,16 +64,12 @@
}
}
- override fun onStart() {
- super.onStart()
+ override fun onResume() {
+ super.onResume()
parent = requireViewById<ViewGroup>(R.id.global_actions_controls)
parent.alpha = 0f
uiController.show(parent, { finish() }, this)
- }
-
- override fun onResume() {
- super.onResume()
ControlsAnimations.enterAnimation(parent).start()
}
@@ -82,8 +78,8 @@
finish()
}
- override fun onStop() {
- super.onStop()
+ override fun onPause() {
+ super.onPause()
uiController.hide()
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index a94df9e..2d200e3 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -24,6 +24,8 @@
import android.content.Context;
import android.content.SharedPreferences;
import android.content.om.OverlayManager;
+import android.hardware.SensorManager;
+import android.hardware.devicestate.DeviceStateManager;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.display.ColorDisplayManager;
import android.os.Handler;
@@ -59,6 +61,7 @@
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.keyguard.LifecycleScreenStatusProvider;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationBarA11yHelper;
import com.android.systemui.navigationbar.NavigationBarController;
@@ -77,6 +80,9 @@
import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.shared.system.WindowManagerWrapper;
+import com.android.unfold.UnfoldTransitionFactory;
+import com.android.unfold.UnfoldTransitionProgressProvider;
+import com.android.unfold.config.UnfoldTransitionConfig;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -378,6 +384,37 @@
/** */
@Provides
@SysUISingleton
+ public UnfoldTransitionProgressProvider provideUnfoldTransitionProgressProvider(
+ Context context,
+ UnfoldTransitionConfig config,
+ LifecycleScreenStatusProvider screenStatusProvider,
+ DeviceStateManager deviceStateManager,
+ SensorManager sensorManager,
+ @Main Executor executor,
+ @Main Handler handler
+ ) {
+ return UnfoldTransitionFactory
+ .createUnfoldTransitionProgressProvider(
+ context,
+ config,
+ screenStatusProvider,
+ deviceStateManager,
+ sensorManager,
+ handler,
+ executor
+ );
+ }
+
+ /** */
+ @Provides
+ @SysUISingleton
+ public UnfoldTransitionConfig provideUnfoldTransitionConfig(Context context) {
+ return UnfoldTransitionFactory.createConfig(context);
+ }
+
+ /** */
+ @Provides
+ @SysUISingleton
public Choreographer providesChoreographer() {
return Choreographer.getInstance();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 954ba79..4d1608f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -41,6 +41,7 @@
import android.content.res.Resources;
import android.hardware.SensorManager;
import android.hardware.SensorPrivacyManager;
+import android.hardware.devicestate.DeviceStateManager;
import android.hardware.display.ColorDisplayManager;
import android.hardware.display.DisplayManager;
import android.hardware.face.FaceManager;
@@ -159,6 +160,12 @@
@Provides
@Singleton
+ static DeviceStateManager provideDeviceStateManager(Context context) {
+ return context.getSystemService(DeviceStateManager.class);
+ }
+
+ @Provides
+ @Singleton
static IActivityManager provideIActivityManager() {
return ActivityManager.getService();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 62b92cb..391e6de 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -18,14 +18,26 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.RemoteAnimationTarget.MODE_CLOSING;
+import static android.view.RemoteAnimationTarget.MODE_OPENING;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
+import static android.view.WindowManager.TRANSIT_OLD_NONE;
+import static android.view.WindowManager.TransitionOldType;
+import static android.view.WindowManager.TransitionType;
+import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.Service;
+import android.app.WindowConfiguration;
import android.content.Intent;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
import android.os.Debug;
@@ -42,8 +54,13 @@
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition;
import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl;
import android.view.WindowManager;
import android.view.WindowManagerPolicyConstants;
+import android.window.IRemoteTransition;
+import android.window.IRemoteTransitionFinishedCallback;
+import android.window.TransitionFilter;
+import android.window.TransitionInfo;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IKeyguardDrawnCallback;
@@ -51,8 +68,11 @@
import com.android.internal.policy.IKeyguardService;
import com.android.internal.policy.IKeyguardStateCallback;
import com.android.systemui.SystemUIApplication;
+import com.android.wm.shell.transition.ShellTransitions;
import com.android.wm.shell.transition.Transitions;
+import java.util.ArrayList;
+
import javax.inject.Inject;
public class KeyguardService extends Service {
@@ -79,40 +99,163 @@
* @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
*/
public static boolean sEnableRemoteKeyguardGoingAwayAnimation =
- !Transitions.ENABLE_SHELL_TRANSITIONS && sEnableRemoteKeyguardAnimation >= 1;
+ sEnableRemoteKeyguardAnimation >= 1;
/**
* @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
*/
public static boolean sEnableRemoteKeyguardOccludeAnimation =
- !Transitions.ENABLE_SHELL_TRANSITIONS && sEnableRemoteKeyguardAnimation >= 2;
+ sEnableRemoteKeyguardAnimation >= 2;
private final KeyguardViewMediator mKeyguardViewMediator;
private final KeyguardLifecyclesDispatcher mKeyguardLifecyclesDispatcher;
+ private static int newModeToLegacyMode(int newMode) {
+ switch (newMode) {
+ case WindowManager.TRANSIT_OPEN:
+ case WindowManager.TRANSIT_TO_FRONT:
+ return MODE_OPENING;
+ case WindowManager.TRANSIT_CLOSE:
+ case WindowManager.TRANSIT_TO_BACK:
+ return MODE_CLOSING;
+ default:
+ return 2; // MODE_CHANGING
+ }
+ }
+
+ private static RemoteAnimationTarget[] wrap(TransitionInfo info, boolean wallpapers) {
+ final ArrayList<RemoteAnimationTarget> out = new ArrayList<>();
+ for (int i = 0; i < info.getChanges().size(); i++) {
+ boolean changeIsWallpaper =
+ (info.getChanges().get(i).getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0;
+ if (wallpapers != changeIsWallpaper) continue;
+
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
+ final int taskId = taskInfo != null ? change.getTaskInfo().taskId : -1;
+ boolean isNotInRecents;
+ WindowConfiguration windowConfiguration = null;
+ if (taskInfo != null) {
+ if (taskInfo.getConfiguration() != null) {
+ windowConfiguration =
+ change.getTaskInfo().getConfiguration().windowConfiguration;
+ }
+ isNotInRecents = !change.getTaskInfo().isRunning;
+ } else {
+ isNotInRecents = true;
+ }
+ Rect localBounds = new Rect(change.getEndAbsBounds());
+ localBounds.offsetTo(change.getEndRelOffset().x, change.getEndRelOffset().y);
+
+ out.add(new RemoteAnimationTarget(
+ taskId,
+ newModeToLegacyMode(change.getMode()),
+ change.getLeash(),
+ (change.getFlags() & TransitionInfo.FLAG_TRANSLUCENT) != 0
+ || (change.getFlags() & TransitionInfo.FLAG_SHOW_WALLPAPER) != 0,
+ null /* clipRect */,
+ new Rect(0, 0, 0, 0) /* contentInsets */,
+ info.getChanges().size() - i,
+ new Point(), localBounds, new Rect(change.getEndAbsBounds()),
+ windowConfiguration, isNotInRecents, null /* startLeash */,
+ change.getStartAbsBounds(), taskInfo));
+ }
+ return out.toArray(new RemoteAnimationTarget[out.size()]);
+ }
+
+ private static @TransitionOldType int getTransitionOldType(@TransitionType int type,
+ RemoteAnimationTarget[] apps) {
+ if (type == TRANSIT_KEYGUARD_GOING_AWAY) {
+ return apps.length == 0 ? TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER
+ : TRANSIT_OLD_KEYGUARD_GOING_AWAY;
+ } else if (type == TRANSIT_KEYGUARD_OCCLUDE) {
+ return TRANSIT_OLD_KEYGUARD_OCCLUDE;
+ } else if (type == TRANSIT_KEYGUARD_UNOCCLUDE) {
+ return TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
+ } else {
+ Slog.d(TAG, "Unexpected transit type: " + type);
+ return TRANSIT_OLD_NONE;
+ }
+ }
+
+ private static IRemoteTransition wrap(IRemoteAnimationRunner runner) {
+ return new IRemoteTransition.Stub() {
+ @Override
+ public void startAnimation(IBinder transition, TransitionInfo info,
+ SurfaceControl.Transaction t, IRemoteTransitionFinishedCallback finishCallback)
+ throws RemoteException {
+ Slog.d(TAG, "Starts IRemoteAnimationRunner: info=" + info);
+ final RemoteAnimationTarget[] apps = wrap(info, false /* wallpapers */);
+ final RemoteAnimationTarget[] wallpapers = wrap(info, true /* wallpapers */);
+ final RemoteAnimationTarget[] nonApps = new RemoteAnimationTarget[0];
+
+ // TODO: Remove this, and update alpha value in the IAnimationRunner.
+ for (TransitionInfo.Change change : info.getChanges()) {
+ t.setAlpha(change.getLeash(), 1.0f);
+ }
+ t.apply();
+ runner.onAnimationStart(getTransitionOldType(info.getType(), apps),
+ apps, wallpapers, nonApps,
+ new IRemoteAnimationFinishedCallback.Stub() {
+ @Override
+ public void onAnimationFinished() throws RemoteException {
+ Slog.d(TAG, "Finish IRemoteAnimationRunner.");
+ finishCallback.onTransitionFinished(null /* wct */, null /* t */);
+ }
+ }
+ );
+ }
+
+ public void mergeAnimation(IBinder transition, TransitionInfo info,
+ SurfaceControl.Transaction t, IBinder mergeTarget,
+ IRemoteTransitionFinishedCallback finishCallback) {
+
+ }
+ };
+ }
+
@Inject
public KeyguardService(KeyguardViewMediator keyguardViewMediator,
- KeyguardLifecyclesDispatcher keyguardLifecyclesDispatcher) {
+ KeyguardLifecyclesDispatcher keyguardLifecyclesDispatcher,
+ ShellTransitions shellTransitions) {
super();
mKeyguardViewMediator = keyguardViewMediator;
mKeyguardLifecyclesDispatcher = keyguardLifecyclesDispatcher;
- RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
- if (sEnableRemoteKeyguardGoingAwayAnimation) {
- final RemoteAnimationAdapter exitAnimationAdapter =
- new RemoteAnimationAdapter(mExitAnimationRunner, 0, 0);
- definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY, exitAnimationAdapter);
- definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
- exitAnimationAdapter);
+ if (shellTransitions != null && Transitions.ENABLE_SHELL_TRANSITIONS) {
+ if (sEnableRemoteKeyguardGoingAwayAnimation) {
+ Slog.d(TAG, "KeyguardService registerRemote: TRANSIT_KEYGUARD_GOING_AWAY");
+ TransitionFilter f = new TransitionFilter();
+ f.mTypeSet = new int[]{TRANSIT_KEYGUARD_GOING_AWAY};
+ shellTransitions.registerRemote(f, wrap(mExitAnimationRunner));
+ }
+ if (sEnableRemoteKeyguardOccludeAnimation) {
+ Slog.d(TAG, "KeyguardService registerRemote: TRANSIT_KEYGUARD_(UN)OCCLUDE");
+ TransitionFilter f = new TransitionFilter();
+ f.mTypeSet = new int[]{TRANSIT_KEYGUARD_OCCLUDE, TRANSIT_KEYGUARD_UNOCCLUDE};
+ shellTransitions.registerRemote(f, wrap(mOccludeAnimationRunner));
+ }
+ } else {
+ RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
+ if (sEnableRemoteKeyguardGoingAwayAnimation) {
+ final RemoteAnimationAdapter exitAnimationAdapter =
+ new RemoteAnimationAdapter(mExitAnimationRunner, 0, 0);
+ definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY,
+ exitAnimationAdapter);
+ definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
+ exitAnimationAdapter);
+ }
+ if (sEnableRemoteKeyguardOccludeAnimation) {
+ final RemoteAnimationAdapter occludeAnimationAdapter =
+ new RemoteAnimationAdapter(mOccludeAnimationRunner, 0, 0);
+ definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_OCCLUDE,
+ occludeAnimationAdapter);
+ definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_UNOCCLUDE,
+ occludeAnimationAdapter);
+ }
+ ActivityTaskManager.getInstance().registerRemoteAnimationsForDisplay(
+ DEFAULT_DISPLAY, definition);
}
- if (sEnableRemoteKeyguardOccludeAnimation) {
- final RemoteAnimationAdapter occludeAnimationAdapter =
- new RemoteAnimationAdapter(mOccludeAnimationRunner, 0, 0);
- definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_OCCLUDE, occludeAnimationAdapter);
- definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_UNOCCLUDE, occludeAnimationAdapter);
- }
- ActivityTaskManager.getInstance().registerRemoteAnimationsForDisplay(
- DEFAULT_DISPLAY, definition);
}
@Override
@@ -145,10 +288,10 @@
RemoteAnimationTarget[] wallpapers,
RemoteAnimationTarget[] nonApps,
IRemoteAnimationFinishedCallback finishedCallback) {
- Trace.beginSection("KeyguardService.mBinder#startKeyguardExitAnimation");
+ Trace.beginSection("mExitAnimationRunner.onAnimationStart#startKeyguardExitAnimation");
checkPermission();
mKeyguardViewMediator.startKeyguardExitAnimation(transit, apps, wallpapers,
- null /* nonApps */, finishedCallback);
+ nonApps, finishedCallback);
Trace.endSection();
}
@@ -166,14 +309,14 @@
RemoteAnimationTarget[] wallpapers,
RemoteAnimationTarget[] nonApps,
IRemoteAnimationFinishedCallback finishedCallback) {
+ Slog.d(TAG, "mOccludeAnimationRunner.onAnimationStart: transit=" + transit);
try {
if (transit == TRANSIT_OLD_KEYGUARD_OCCLUDE) {
mBinder.setOccluded(true /* isOccluded */, true /* animate */);
} else if (transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE) {
mBinder.setOccluded(false /* isOccluded */, true /* animate */);
}
- // TODO(bc-unlock): Implement occlude/unocclude animation applied on apps,
- // wallpapers and nonApps.
+ // TODO(bc-unlock): Implement (un)occlude animation.
finishedCallback.onAnimationFinished();
} catch (RemoteException e) {
Slog.e(TAG, "RemoteException");
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 941f2c6..a5fe9015 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -222,6 +222,11 @@
keyguardViewController.hide(startTime, 350)
surfaceBehindEntryAnimator.start()
}
+
+ // Finish the keyguard remote animation if the dismiss amount has crossed the threshold.
+ // Check it here in case there is no more change to the dismiss amount after the last change
+ // that starts the keyguard animation. @see #updateKeyguardViewMediatorIfThresholdsReached()
+ finishKeyguardExitRemoteAnimationIfReachThreshold()
}
fun notifyCancelKeyguardExitAnimation() {
@@ -353,16 +358,6 @@
}
val dismissAmount = keyguardStateController.dismissAmount
-
- // Hide the keyguard if we're fully dismissed, or if we're swiping to dismiss and have
- // crossed the threshold to finish the dismissal.
- val reachedHideKeyguardThreshold = (dismissAmount >= 1f ||
- (keyguardStateController.isDismissingFromSwipe &&
- // Don't hide if we're flinging during a swipe, since we need to finish
- // animating it out. This will be called again after the fling ends.
- !keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture &&
- dismissAmount >= DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD))
-
if (dismissAmount >= DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD &&
!keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) {
// We passed the threshold, and we're not yet showing the surface behind the
@@ -375,9 +370,35 @@
// out.
keyguardViewMediator.get().hideSurfaceBehindKeyguard()
fadeOutSurfaceBehind()
- } else if (keyguardViewMediator.get()
- .isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe &&
- reachedHideKeyguardThreshold) {
+ } else {
+ finishKeyguardExitRemoteAnimationIfReachThreshold()
+ }
+ }
+
+ /**
+ * Hides the keyguard if we're fully dismissed, or if we're swiping to dismiss and have crossed
+ * the threshold to finish the dismissal.
+ */
+ private fun finishKeyguardExitRemoteAnimationIfReachThreshold() {
+ // no-op if keyguard is not showing or animation is not enabled.
+ if (!KeyguardService.sEnableRemoteKeyguardGoingAwayAnimation ||
+ !keyguardViewController.isShowing) {
+ return
+ }
+
+ // no-op if animation is not requested yet.
+ if (!keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard() ||
+ !keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe) {
+ return
+ }
+
+ val dismissAmount = keyguardStateController.dismissAmount
+ if (dismissAmount >= 1f ||
+ (keyguardStateController.isDismissingFromSwipe &&
+ // Don't hide if we're flinging during a swipe, since we need to finish
+ // animating it out. This will be called again after the fling ends.
+ !keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture &&
+ dismissAmount >= DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD)) {
keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished(false /* cancelled */)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index c7c2590..d12c763 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2369,7 +2369,7 @@
final boolean wasShowing = mShowing;
onKeyguardExitFinished();
- if (mKeyguardStateController.isDismissingFromSwipe() || !wasShowing) {
+ if (mKeyguardStateController.isDismissingFromSwipe() || wasShowing) {
mKeyguardUnlockAnimationControllerLazy.get().hideKeyguardViewAfterRemoteAnimation();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/LifecycleScreenStatusProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/LifecycleScreenStatusProvider.kt
new file mode 100644
index 0000000..d8905a0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/LifecycleScreenStatusProvider.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.keyguard
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.unfold.updates.screen.ScreenStatusProvider
+import com.android.unfold.updates.screen.ScreenStatusProvider.ScreenListener
+import javax.inject.Inject
+
+@SysUISingleton
+class LifecycleScreenStatusProvider @Inject constructor(screenLifecycle: ScreenLifecycle) :
+ ScreenStatusProvider, ScreenLifecycle.Observer {
+
+ init {
+ screenLifecycle.addObserver(this)
+ }
+
+ private val listeners: MutableList<ScreenListener> = mutableListOf()
+
+ override fun removeCallback(listener: ScreenListener) {
+ listeners.remove(listener)
+ }
+
+ override fun addCallback(listener: ScreenListener) {
+ listeners.add(listener)
+ }
+
+ override fun onScreenTurnedOn() {
+ listeners.forEach(ScreenListener::onScreenTurnedOn)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 683b5c3..4a67e94 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -25,6 +25,8 @@
import static android.app.StatusBarManager.windowStateToString;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE;
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.containsType;
@@ -92,8 +94,8 @@
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.IWindowManager;
-import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
+import android.view.InsetsVisibilities;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -290,7 +292,7 @@
@Override
public boolean shouldHideOnTouch() {
- return !mNotificationRemoteInputManager.getController().isRemoteInputActive();
+ return !mNotificationRemoteInputManager.isRemoteInputActive();
}
@Override
@@ -589,12 +591,13 @@
mDeviceProvisionedController.addCallback(mUserSetupListener);
mNotificationShadeDepthController.addListener(mDepthListener);
- setAccessibilityFloatingMenuModeIfNeeded();
+ updateAccessibilityButtonModeIfNeeded();
return barView;
}
public void destroyView() {
+ setAutoHideController(/* autoHideController */ null);
mCommandQueue.removeCallback(this);
mContext.getSystemService(WindowManager.class).removeViewImmediate(
mNavigationBarView.getRootView());
@@ -917,6 +920,11 @@
@Override
public void onRotationProposal(final int rotation, boolean isValid) {
+ // The CommandQueue callbacks are added when the view is created to ensure we track other
+ // states, but until the view is attached (at the next traversal), the view's display is
+ // not valid. Just ignore the rotation in this case.
+ if (!mNavigationBarView.isAttachedToWindow()) return;
+
final int winRotation = mNavigationBarView.getDisplay().getRotation();
final boolean rotateSuggestionsDisabled = RotationButtonController
.hasDisable2RotateSuggestionFlag(mDisabledFlags2);
@@ -964,7 +972,7 @@
@Override
public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, InsetsState requestedState, String packageName) {
+ @Behavior int behavior, InsetsVisibilities requestedVisibilities, String packageName) {
if (displayId != mDisplayId) {
return;
}
@@ -1379,11 +1387,31 @@
updateSystemUiStateFlags(a11yFlags);
}
- private void setAccessibilityFloatingMenuModeIfNeeded() {
- if (QuickStepContract.isGesturalMode(mNavBarMode)) {
+ private void updateAccessibilityButtonModeIfNeeded() {
+ final int mode = Settings.Secure.getIntForUser(mContentResolver,
+ Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
+ ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT);
+
+ // ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU is compatible under gestural or non-gestural
+ // mode, so we don't need to update it.
+ if (mode == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) {
+ return;
+ }
+
+ // ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR is incompatible under gestural mode. Need to
+ // force update to ACCESSIBILITY_BUTTON_MODE_GESTURE.
+ if (QuickStepContract.isGesturalMode(mNavBarMode)
+ && mode == ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR) {
+ Settings.Secure.putIntForUser(mContentResolver,
+ Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_GESTURE,
+ UserHandle.USER_CURRENT);
+ // ACCESSIBILITY_BUTTON_MODE_GESTURE is incompatible under non gestural mode. Need to
+ // force update to ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR.
+ } else if (!QuickStepContract.isGesturalMode(mNavBarMode)
+ && mode == ACCESSIBILITY_BUTTON_MODE_GESTURE) {
Settings.Secure.putIntForUser(mContentResolver,
Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
- ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU, UserHandle.USER_CURRENT);
+ ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT);
}
}
@@ -1462,7 +1490,7 @@
}
/** Sets {@link AutoHideController} to the navigation bar. */
- public void setAutoHideController(AutoHideController autoHideController) {
+ private void setAutoHideController(AutoHideController autoHideController) {
mAutoHideController = autoHideController;
if (mAutoHideController != null) {
mAutoHideController.setNavigationBar(mAutoHideUiElement);
@@ -1511,7 +1539,7 @@
}
}
updateScreenPinningGestures();
- setAccessibilityFloatingMenuModeIfNeeded();
+ updateAccessibilityButtonModeIfNeeded();
if (!canShowSecondaryHandle()) {
resetSecondaryHandle();
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 458c50d..543004e 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -402,7 +402,6 @@
void removeNavigationBar(int displayId) {
NavigationBar navBar = mNavigationBars.get(displayId);
if (navBar != null) {
- navBar.setAutoHideController(/* autoHideController */ null);
navBar.destroyView();
mNavigationBars.remove(displayId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 808b7e2..2d36de3 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -98,6 +98,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
+import java.util.concurrent.Executor;
import java.util.function.Consumer;
public class NavigationBarView extends FrameLayout implements
@@ -354,6 +355,7 @@
mEdgeBackGestureHandler = Dependency.get(EdgeBackGestureHandler.Factory.class)
.create(mContext);
mEdgeBackGestureHandler.setStateChangeCallback(this::updateStates);
+ Executor backgroundExecutor = Dependency.get(Dependency.BACKGROUND_EXECUTOR);
mRegionSamplingHelper = new RegionSamplingHelper(this,
new RegionSamplingHelper.SamplingCallback() {
@Override
@@ -376,7 +378,7 @@
public boolean isSamplingEnabled() {
return isGesturalModeOnDefaultDisplay(getContext(), mNavBarMode);
}
- });
+ }, backgroundExecutor);
mNavBarOverlayController = Dependency.get(NavigationBarOverlayController.class);
if (mNavBarOverlayController.isNavigationBarOverlayEnabled()) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index 1d44146..fe24ecd 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -26,7 +26,7 @@
import android.inputmethodservice.InputMethodService;
import android.os.IBinder;
-import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import com.android.internal.view.AppearanceRegion;
import com.android.systemui.model.SysUiState;
@@ -109,7 +109,7 @@
@Override
public void onSystemBarAttributesChanged(int displayId, int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, int behavior,
- InsetsState requestedState, String packageName) {
+ InsetsVisibilities requestedVisibilities, String packageName) {
mOverviewProxyService.onSystemBarAttributesChanged(displayId, behavior);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
index 7fdb79e..ea04cef 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
@@ -58,6 +58,7 @@
import com.android.systemui.statusbar.VibratorHelper;
import java.io.PrintWriter;
+import java.util.concurrent.Executor;
public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPlugin {
@@ -349,6 +350,7 @@
.getDimension(R.dimen.navigation_edge_action_drag_threshold);
setVisibility(GONE);
+ Executor backgroundExecutor = Dependency.get(Dependency.BACKGROUND_EXECUTOR);
boolean isPrimaryDisplay = mContext.getDisplayId() == DEFAULT_DISPLAY;
mRegionSamplingHelper = new RegionSamplingHelper(this,
new RegionSamplingHelper.SamplingCallback() {
@@ -366,7 +368,7 @@
public boolean isSamplingEnabled() {
return isPrimaryDisplay;
}
- });
+ }, backgroundExecutor);
mRegionSamplingHelper.setWindowVisible(true);
mShowProtection = !isPrimaryDisplay;
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/RegionSamplingHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/RegionSamplingHelper.java
index 560d89a..c9a9399 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/RegionSamplingHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/RegionSamplingHelper.java
@@ -30,6 +30,7 @@
import com.android.systemui.R;
import java.io.PrintWriter;
+import java.util.concurrent.Executor;
/**
* A helper class to sample regions on the screen and inspect its luminosity.
@@ -52,6 +53,7 @@
*/
private final Rect mRegisteredSamplingBounds = new Rect();
private final SamplingCallback mCallback;
+ private final Executor mBackgroundExecutor;
private boolean mSamplingEnabled = false;
private boolean mSamplingListenerRegistered = false;
@@ -82,7 +84,9 @@
}
};
- public RegionSamplingHelper(View sampledView, SamplingCallback samplingCallback) {
+ public RegionSamplingHelper(View sampledView, SamplingCallback samplingCallback,
+ Executor backgroundExecutor) {
+ mBackgroundExecutor = backgroundExecutor;
mSamplingListener = new CompositionSamplingListener(
sampledView.getContext().getMainExecutor()) {
@Override
@@ -183,10 +187,13 @@
// We only want to reregister if something actually changed
unregisterSamplingListener();
mSamplingListenerRegistered = true;
- CompositionSamplingListener.register(mSamplingListener, DEFAULT_DISPLAY,
- stopLayerControl, mSamplingRequestBounds);
+ SurfaceControl registeredStopLayer = stopLayerControl;
+ mBackgroundExecutor.execute(() -> {
+ CompositionSamplingListener.register(mSamplingListener, DEFAULT_DISPLAY,
+ registeredStopLayer, mSamplingRequestBounds);
+ });
mRegisteredSamplingBounds.set(mSamplingRequestBounds);
- mRegisteredStopLayer = stopLayerControl;
+ mRegisteredStopLayer = registeredStopLayer;
}
mFirstSamplingAfterStart = false;
} else {
@@ -199,7 +206,9 @@
mSamplingListenerRegistered = false;
mRegisteredStopLayer = null;
mRegisteredSamplingBounds.setEmpty();
- CompositionSamplingListener.unregister(mSamplingListener);
+ mBackgroundExecutor.execute(() -> {
+ CompositionSamplingListener.unregister(mSamplingListener);
+ });
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index a318073..4fcd46c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -423,6 +423,9 @@
if (mQsPanelController.shouldUseHorizontalLayout()
&& mQsPanelController.mMediaHost.hostView != null) {
builder.addFloat(mQsPanelController.mMediaHost.hostView, "alpha", 0, 1);
+ } else {
+ // In portrait, media view should always be visible
+ mQsPanelController.mMediaHost.hostView.setAlpha(1.0f);
}
mAllPagesDelayedAnimator = builder.build();
mAllViews.add(mSecurityFooter.getView());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index d56fe48..dd81b65 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -48,6 +48,7 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.util.InjectionInflationController;
@@ -69,6 +70,7 @@
private final Rect mQsBounds = new Rect();
private final StatusBarStateController mStatusBarStateController;
private final FalsingManager mFalsingManager;
+ private final KeyguardBypassController mBypassController;
private boolean mQsExpanded;
private boolean mHeaderAnimating;
private boolean mStackScrollerOverscrolling;
@@ -135,6 +137,7 @@
StatusBarStateController statusBarStateController, CommandQueue commandQueue,
QSDetailDisplayer qsDetailDisplayer, @Named(QS_PANEL) MediaHost qsMediaHost,
@Named(QUICK_QS_PANEL) MediaHost qqsMediaHost,
+ KeyguardBypassController keyguardBypassController,
QSFragmentComponent.Factory qsComponentFactory,
FalsingManager falsingManager) {
mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler;
@@ -147,6 +150,7 @@
commandQueue.observe(getLifecycle(), this);
mHost = qsTileHost;
mFalsingManager = falsingManager;
+ mBypassController = keyguardBypassController;
mStatusBarStateController = statusBarStateController;
}
@@ -385,16 +389,8 @@
return mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
}
- @Override
- public void setPulseExpanding(boolean pulseExpanding) {
- if (pulseExpanding != mPulseExpanding) {
- mPulseExpanding = pulseExpanding;
- updateShowCollapsedOnKeyguard();
- }
- }
-
private void updateShowCollapsedOnKeyguard() {
- boolean showCollapsed = mPulseExpanding || mTransitioningToFullShade;
+ boolean showCollapsed = mBypassController.getBypassEnabled() || mTransitioningToFullShade;
if (showCollapsed != mShowCollapsedOnKeyguard) {
mShowCollapsedOnKeyguard = showCollapsed;
updateQsState();
@@ -724,5 +720,6 @@
public void onStateChanged(int newState) {
mState = newState;
setKeyguardShowing(newState == StatusBarState.KEYGUARD);
+ updateShowCollapsedOnKeyguard();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
index f66b722..bc21b2d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
@@ -69,7 +69,7 @@
private var hasControlsApps = AtomicBoolean(false)
- private val icon = ResourceIcon.get(R.drawable.ic_device_light)
+ private val icon = ResourceIcon.get(R.drawable.controls_icon)
private val listingCallback = object : ControlsListingController.ControlsListingCallback {
override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) {
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
index a9ebcad..9e4a355 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
@@ -354,9 +354,10 @@
convertGammaToLinearFloat(value, minBacklight, maxBacklight),
maxBacklight);
if (stopTracking) {
- // TODO(brightnessfloat): change to use float value instead.
+ // Log brightness as a value between 0-1000 directly correlated to brightnesses 0-1.0
MetricsLogger.action(mContext, metric,
- BrightnessSynchronizer.brightnessFloatToInt(valFloat));
+ Math.round(MathUtils.constrainedMap(0, 1000, PowerManager.BRIGHTNESS_MIN,
+ PowerManager.BRIGHTNESS_MAX, valFloat)));
}
setBrightness(valFloat);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index c7f8dcf..90158c32 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -50,8 +50,8 @@
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
-import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
+import android.view.InsetsVisibilities;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
@@ -338,7 +338,8 @@
*/
default void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, InsetsState requestedState, String packageName) { }
+ @Behavior int behavior, InsetsVisibilities requestedVisibilities,
+ String packageName) { }
/**
* @see IStatusBar#showTransient(int, int[]).
@@ -997,7 +998,7 @@
@Override
public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, InsetsState requestedState, String packageName) {
+ @Behavior int behavior, InsetsVisibilities requestedVisibilities, String packageName) {
synchronized (mLock) {
SomeArgs args = SomeArgs.obtain();
args.argi1 = displayId;
@@ -1005,7 +1006,7 @@
args.argi3 = navbarColorManagedByIme ? 1 : 0;
args.arg1 = appearanceRegions;
args.argi4 = behavior;
- args.arg2 = requestedState;
+ args.arg2 = requestedVisibilities;
args.arg3 = packageName;
mHandler.obtainMessage(MSG_SYSTEM_BAR_CHANGED, args).sendToTarget();
}
@@ -1389,7 +1390,7 @@
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).onSystemBarAttributesChanged(args.argi1, args.argi2,
(AppearanceRegion[]) args.arg1, args.argi3 == 1, args.argi4,
- (InsetsState) args.arg2, (String) args.arg3);
+ (InsetsVisibilities) args.arg2, (String) args.arg3);
}
args.recycle();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 4d15a0a..92922b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -77,6 +77,7 @@
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -100,7 +101,7 @@
private static final boolean DEBUG_CHARGING_SPEED = false;
private static final int MSG_HIDE_TRANSIENT = 1;
- private static final int MSG_SWIPE_UP_TO_UNLOCK = 2;
+ private static final int MSG_SHOW_ACTION_TO_UNLOCK = 2;
private static final long TRANSIENT_BIOMETRIC_ERROR_TIMEOUT = 1300;
private static final float BOUNCE_ANIMATION_FINAL_Y = 0f;
@@ -121,6 +122,7 @@
private final LockPatternUtils mLockPatternUtils;
private final IActivityManager mIActivityManager;
private final FalsingManager mFalsingManager;
+ private final KeyguardBypassController mKeyguardBypassController;
protected KeyguardIndicationRotateTextViewController mRotateTextViewController;
private BroadcastReceiver mBroadcastReceiver;
@@ -175,7 +177,8 @@
@Main DelayableExecutor executor,
FalsingManager falsingManager,
LockPatternUtils lockPatternUtils,
- IActivityManager iActivityManager) {
+ IActivityManager iActivityManager,
+ KeyguardBypassController keyguardBypassController) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
mDevicePolicyManager = devicePolicyManager;
@@ -191,6 +194,7 @@
mLockPatternUtils = lockPatternUtils;
mIActivityManager = iActivityManager;
mFalsingManager = falsingManager;
+ mKeyguardBypassController = keyguardBypassController;
}
@@ -593,7 +597,7 @@
mTransientIndication = transientIndication;
mHideTransientMessageOnScreenOff = hideOnScreenOff && transientIndication != null;
mHandler.removeMessages(MSG_HIDE_TRANSIENT);
- mHandler.removeMessages(MSG_SWIPE_UP_TO_UNLOCK);
+ mHandler.removeMessages(MSG_SHOW_ACTION_TO_UNLOCK);
if (mDozing && !TextUtils.isEmpty(mTransientIndication)) {
// Make sure this doesn't get stuck and burns in. Acquire wakelock until its cleared.
mWakeLock.setAcquired(true);
@@ -785,27 +789,35 @@
public void handleMessage(Message msg) {
if (msg.what == MSG_HIDE_TRANSIENT) {
hideTransientIndication();
- } else if (msg.what == MSG_SWIPE_UP_TO_UNLOCK) {
- showSwipeUpToUnlock();
+ } else if (msg.what == MSG_SHOW_ACTION_TO_UNLOCK) {
+ showActionToUnlock();
}
}
};
- private void showSwipeUpToUnlock() {
+ /**
+ * Show message on the keyguard for how the user can unlock/enter their device.
+ */
+ public void showActionToUnlock() {
if (mDozing) {
return;
}
if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) {
- return; // udfps affordance is highlighted, no need to surface face auth error
- } else {
+ return; // udfps affordance is highlighted, no need to show action to unlock
+ } else if (mKeyguardUpdateMonitor.isFaceEnrolled()) {
String message = mContext.getString(R.string.keyguard_retry);
mStatusBarKeyguardViewManager.showBouncerMessage(message, mInitialTextColorState);
}
} else if (mKeyguardUpdateMonitor.isScreenOn()) {
- showTransientIndication(mContext.getString(R.string.keyguard_unlock),
- false /* isError */, true /* hideOnScreenOff */);
+ if (mKeyguardUpdateMonitor.isUdfpsAvailable()) {
+ showTransientIndication(mContext.getString(R.string.keyguard_unlock_press),
+ false /* isError */, true /* hideOnScreenOff */);
+ } else {
+ showTransientIndication(mContext.getString(R.string.keyguard_unlock),
+ false /* isError */, true /* hideOnScreenOff */);
+ }
}
}
@@ -885,13 +897,16 @@
mStatusBarKeyguardViewManager.showBouncerMessage(helpString,
mInitialTextColorState);
} else if (mKeyguardUpdateMonitor.isScreenOn()) {
- if (biometricSourceType == BiometricSourceType.FACE && shouldSuppressFaceMsg()) {
+ if (biometricSourceType == BiometricSourceType.FACE
+ && shouldSuppressFaceMsgAndShowTryFingerprintMsg()) {
+ // suggest trying fingerprint
+ showTransientIndication(R.string.keyguard_try_fingerprint);
return;
}
showTransientIndication(helpString, false /* isError */, showSwipeToUnlock);
}
if (showSwipeToUnlock) {
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SWIPE_UP_TO_UNLOCK),
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SHOW_ACTION_TO_UNLOCK),
TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
}
}
@@ -903,9 +918,11 @@
return;
}
if (biometricSourceType == BiometricSourceType.FACE
- && shouldSuppressFaceMsg()
+ && shouldSuppressFaceMsgAndShowTryFingerprintMsg()
&& !mStatusBarKeyguardViewManager.isBouncerShowing()
&& mKeyguardUpdateMonitor.isScreenOn()) {
+ // suggest trying fingerprint
+ showTransientIndication(R.string.keyguard_try_fingerprint);
return;
}
if (msgId == FaceManager.FACE_ERROR_TIMEOUT) {
@@ -923,7 +940,7 @@
);
} else {
// suggest swiping up to unlock (try face auth again or swipe up to bouncer)
- showSwipeUpToUnlock();
+ showActionToUnlock();
}
} else if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
mStatusBarKeyguardViewManager.showBouncerMessage(errString, mInitialTextColorState);
@@ -956,7 +973,7 @@
|| msgId == FingerprintManager.FINGERPRINT_ERROR_USER_CANCELED);
}
- private boolean shouldSuppressFaceMsg() {
+ private boolean shouldSuppressFaceMsgAndShowTryFingerprintMsg() {
// For dual biometric, don't show face auth messages
return mKeyguardUpdateMonitor.isFingerprintDetectionRunning()
&& mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
@@ -1005,6 +1022,11 @@
boolean isStrongBiometric) {
super.onBiometricAuthenticated(userId, biometricSourceType, isStrongBiometric);
mHandler.sendEmptyMessage(MSG_HIDE_TRANSIENT);
+
+ if (biometricSourceType == BiometricSourceType.FACE
+ && !mKeyguardBypassController.canBypass()) {
+ mHandler.sendEmptyMessage(MSG_SHOW_ACTION_TO_UNLOCK);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index 538db61..8780ad8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -83,6 +83,35 @@
}
}
+class LinearLightRevealEffect(private val isVertical: Boolean) : LightRevealEffect {
+
+ private val INTERPOLATOR = Interpolators.FAST_OUT_SLOW_IN_REVERSE
+
+ override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {
+ val interpolatedAmount = INTERPOLATOR.getInterpolation(amount)
+
+ // TODO(b/193801466): add alpha reveal in the beginning as well
+ scrim.revealGradientEndColorAlpha =
+ 1f - LightRevealEffect.getPercentPastThreshold(interpolatedAmount, threshold = 0.6f)
+
+ if (isVertical) {
+ scrim.setRevealGradientBounds(
+ left = scrim.width / 2 - (scrim.width / 2) * interpolatedAmount,
+ top = 0f,
+ right = scrim.width / 2 + (scrim.width / 2) * interpolatedAmount,
+ bottom = scrim.height.toFloat()
+ )
+ } else {
+ scrim.setRevealGradientBounds(
+ left = 0f,
+ top = scrim.height / 2 - (scrim.height / 2) * interpolatedAmount,
+ right = scrim.width.toFloat(),
+ bottom = scrim.height / 2 + (scrim.height / 2) * interpolatedAmount
+ )
+ }
+ }
+}
+
class CircleReveal(
/** X-value of the circle center of the reveal. */
val centerX: Float,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index f0da702..ca18b07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -64,6 +64,7 @@
configurationController: ConfigurationController,
falsingManager: FalsingManager
) {
+ private var pulseHeight: Float = 0f
private var useSplitShade: Boolean = false
private lateinit var nsslController: NotificationStackScrollLayoutController
lateinit var notificationPanelController: NotificationPanelViewController
@@ -87,6 +88,12 @@
internal var dragDownAnimator: ValueAnimator? = null
/**
+ * The current pulse height animator if any
+ */
+ @VisibleForTesting
+ internal var pulseHeightAnimator: ValueAnimator? = null
+
+ /**
* Distance that the full shade transition takes in order for scrim to fully transition to
* the shade (in alpha)
*/
@@ -109,6 +116,12 @@
private var nextHideKeyguardNeedsNoAnimation = false
/**
+ * The distance until we're showing the notifications when pulsing
+ */
+ val distanceUntilShowingPulsingNotifications
+ get() = scrimTransitionDistance
+
+ /**
* The udfpsKeyguardViewController if it exists.
*/
var udfpsKeyguardViewController: UdfpsKeyguardViewController? = null
@@ -285,22 +298,26 @@
nsslController.setTransitionToFullShadeAmount(field)
notificationPanelController.setTransitionToFullShadeAmount(field,
false /* animate */, 0 /* delay */)
- val scrimProgress = MathUtils.saturate(field / scrimTransitionDistance)
- scrimController.setTransitionToFullShadeProgress(scrimProgress)
// TODO: appear qs also in split shade
val qsAmount = if (useSplitShade) 0f else field
qS.setTransitionToFullShadeAmount(qsAmount, false /* animate */)
// TODO: appear media also in split shade
val mediaAmount = if (useSplitShade) 0f else field
mediaHierarchyManager.setTransitionToFullShadeAmount(mediaAmount)
- // Fade out all content only visible on the lockscreen
- notificationPanelController.setKeyguardOnlyContentAlpha(1.0f - scrimProgress)
- depthController.transitionToFullShadeProgress = scrimProgress
- udfpsKeyguardViewController?.setTransitionToFullShadeProgress(scrimProgress)
+ transitionToShadeAmountCommon(field)
}
}
}
+ private fun transitionToShadeAmountCommon(dragDownAmount: Float) {
+ val scrimProgress = MathUtils.saturate(dragDownAmount / scrimTransitionDistance)
+ scrimController.setTransitionToFullShadeProgress(scrimProgress)
+ // Fade out all content only visible on the lockscreen
+ notificationPanelController.setKeyguardOnlyContentAlpha(1.0f - scrimProgress)
+ depthController.transitionToFullShadeProgress = scrimProgress
+ udfpsKeyguardViewController?.setTransitionToFullShadeProgress(scrimProgress)
+ }
+
private fun setDragDownAmountAnimated(
target: Float,
delay: Long = 0,
@@ -452,15 +469,19 @@
/**
* Notify this handler that the keyguard was just dismissed and that a animation to
* the full shade should happen.
+ *
+ * @param delay the delay to do the animation with
+ * @param previousState which state were we in when we hid the keyguard?
*/
- fun onHideKeyguard(delay: Long) {
+ fun onHideKeyguard(delay: Long, previousState: Int) {
if (animationHandlerOnKeyguardDismiss != null) {
animationHandlerOnKeyguardDismiss!!.invoke(delay)
animationHandlerOnKeyguardDismiss = null
} else {
if (nextHideKeyguardNeedsNoAnimation) {
nextHideKeyguardNeedsNoAnimation = false
- } else {
+ } else if (previousState != StatusBarState.SHADE_LOCKED) {
+ // No animation necessary if we already were in the shade locked!
performDefaultGoToFullShadeAnimation(delay)
}
}
@@ -478,6 +499,53 @@
notificationPanelController.animateToFullShade(delay)
animateAppear(delay)
}
+
+ //
+ // PULSE EXPANSION
+ //
+
+ /**
+ * Set the height how tall notifications are pulsing. This is only set whenever we are expanding
+ * from a pulse and determines how much the notifications are expanded.
+ */
+ fun setPulseHeight(height: Float, animate: Boolean = false) {
+ if (animate) {
+ val pulseHeightAnimator = ValueAnimator.ofFloat(pulseHeight, height)
+ pulseHeightAnimator.interpolator = Interpolators.FAST_OUT_SLOW_IN
+ pulseHeightAnimator.duration = SPRING_BACK_ANIMATION_LENGTH_MS
+ pulseHeightAnimator.addUpdateListener { animation: ValueAnimator ->
+ setPulseHeight(animation.animatedValue as Float)
+ }
+ pulseHeightAnimator.start()
+ this.pulseHeightAnimator = pulseHeightAnimator
+ } else {
+ pulseHeight = height
+ val overflow = nsslController.setPulseHeight(height)
+ notificationPanelController.setOverStrechAmount(overflow)
+ val transitionHeight = if (keyguardBypassController.bypassEnabled) height else 0.0f
+ transitionToShadeAmountCommon(transitionHeight)
+ }
+ }
+
+ /**
+ * Finish the pulse animation when the touch interaction finishes
+ * @param cancelled was the interaction cancelled and this is a reset?
+ */
+ fun finishPulseAnimation(cancelled: Boolean) {
+ if (cancelled) {
+ setPulseHeight(0f, animate = true)
+ } else {
+ notificationPanelController.onPulseExpansionFinished()
+ setPulseHeight(0f, animate = false)
+ }
+ }
+
+ /**
+ * Notify this class that a pulse expansion is starting
+ */
+ fun onPulseExpansionStarted() {
+ pulseHeightAnimator?.cancel()
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index bc3883c..625d9cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -70,6 +70,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
@@ -136,6 +137,8 @@
protected Callback mCallback;
protected final ArrayList<NotificationLifetimeExtender> mLifetimeExtenders = new ArrayList<>();
+ private final List<RemoteInputController.Callback> mControllerCallbacks = new ArrayList<>();
+
private final InteractionHandler mInteractionHandler = new InteractionHandler() {
@Override
@@ -332,6 +335,11 @@
public void setUpWithCallback(Callback callback, RemoteInputController.Delegate delegate) {
mCallback = callback;
mRemoteInputController = new RemoteInputController(delegate, mRemoteInputUriController);
+ // Register all stored callbacks from before the Controller was initialized.
+ for (RemoteInputController.Callback cb : mControllerCallbacks) {
+ mRemoteInputController.addCallback(cb);
+ }
+ mControllerCallbacks.clear();
mRemoteInputController.addCallback(new RemoteInputController.Callback() {
@Override
public void onRemoteInputSent(NotificationEntry entry) {
@@ -377,6 +385,22 @@
});
}
+ public void addControllerCallback(RemoteInputController.Callback callback) {
+ if (mRemoteInputController != null) {
+ mRemoteInputController.addCallback(callback);
+ } else {
+ mControllerCallbacks.add(callback);
+ }
+ }
+
+ public void removeControllerCallback(RemoteInputController.Callback callback) {
+ if (mRemoteInputController != null) {
+ mRemoteInputController.removeCallback(callback);
+ } else {
+ mControllerCallbacks.remove(callback);
+ }
+ }
+
/**
* Activates a given {@link RemoteInput}
*
@@ -563,17 +587,12 @@
return mLifetimeExtenders;
}
- @Nullable
- public RemoteInputController getController() {
- return mRemoteInputController;
- }
-
@VisibleForTesting
void onPerformRemoveNotification(NotificationEntry entry, final String key) {
if (mKeysKeptForRemoteInputHistory.contains(key)) {
mKeysKeptForRemoteInputHistory.remove(key);
}
- if (mRemoteInputController.isRemoteInputActive(entry)) {
+ if (isRemoteInputActive(entry)) {
entry.mRemoteEditImeVisible = false;
mRemoteInputController.removeRemoteInput(entry, null);
}
@@ -582,7 +601,9 @@
public void onPanelCollapsed() {
for (int i = 0; i < mEntriesKeptForRemoteInputActive.size(); i++) {
NotificationEntry entry = mEntriesKeptForRemoteInputActive.valueAt(i);
- mRemoteInputController.removeRemoteInput(entry, null);
+ if (mRemoteInputController != null) {
+ mRemoteInputController.removeRemoteInput(entry, null);
+ }
if (mNotificationLifetimeFinishedCallback != null) {
mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.getKey());
}
@@ -598,8 +619,7 @@
if (!FORCE_REMOTE_INPUT_HISTORY) {
return false;
}
- return (mRemoteInputController.isSpinning(entry.getKey())
- || entry.hasJustSentRemoteInput());
+ return isSpinning(entry.getKey()) || entry.hasJustSentRemoteInput();
}
/**
@@ -632,8 +652,8 @@
public void checkRemoteInputOutside(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
&& event.getX() == 0 && event.getY() == 0 // a touch outside both bars
- && mRemoteInputController.isRemoteInputActive()) {
- mRemoteInputController.closeRemoteInputs();
+ && isRemoteInputActive()) {
+ closeRemoteInputs();
}
}
@@ -715,6 +735,24 @@
return mEntriesKeptForRemoteInputActive;
}
+ public boolean isRemoteInputActive() {
+ return mRemoteInputController != null && mRemoteInputController.isRemoteInputActive();
+ }
+
+ public boolean isRemoteInputActive(NotificationEntry entry) {
+ return mRemoteInputController != null && mRemoteInputController.isRemoteInputActive(entry);
+ }
+
+ public boolean isSpinning(String entryKey) {
+ return mRemoteInputController != null && mRemoteInputController.isSpinning(entryKey);
+ }
+
+ public void closeRemoteInputs() {
+ if (mRemoteInputController != null) {
+ mRemoteInputController.closeRemoteInputs();
+ }
+ }
+
/**
* NotificationRemoteInputManager has multiple reasons to keep notification lifetime extended
* so we implement multiple NotificationLifetimeExtenders
@@ -822,7 +860,7 @@
protected class RemoteInputActiveExtender extends RemoteInputExtender {
@Override
public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
- return mRemoteInputController.isRemoteInputActive(entry);
+ return isRemoteInputActive(entry);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index b34bfad..761a203 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -19,8 +19,8 @@
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ObjectAnimator
-import android.animation.ValueAnimator
import android.content.Context
+import android.content.res.Configuration
import android.os.PowerManager
import android.os.PowerManager.WAKE_REASON_GESTURE
import android.os.SystemClock
@@ -42,6 +42,7 @@
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.policy.ConfigurationController
import javax.inject.Inject
import kotlin.math.max
@@ -56,18 +57,17 @@
private val bypassController: KeyguardBypassController,
private val headsUpManager: HeadsUpManagerPhone,
private val roundnessManager: NotificationRoundnessManager,
+ private val configurationController: ConfigurationController,
private val statusBarStateController: StatusBarStateController,
private val falsingManager: FalsingManager,
private val lockscreenShadeTransitionController: LockscreenShadeTransitionController,
private val falsingCollector: FalsingCollector
) : Gefingerpoken {
companion object {
- private val RUBBERBAND_FACTOR_STATIC = 0.25f
private val SPRING_BACK_ANIMATION_LENGTH_MS = 375
}
private val mPowerManager: PowerManager?
- private val mMinDragDistance: Int
private var mInitialTouchX: Float = 0.0f
private var mInitialTouchY: Float = 0.0f
var isExpanding: Boolean = false
@@ -81,6 +81,7 @@
topEntry?.let {
roundnessManager.setTrackingHeadsUp(it.row)
}
+ lockscreenShadeTransitionController.onPulseExpansionStarted()
} else {
roundnessManager.setTrackingHeadsUp(null)
if (!leavingLockscreen) {
@@ -93,8 +94,8 @@
}
var leavingLockscreen: Boolean = false
private set
- private val mTouchSlop: Float
- private lateinit var overStretchHandler: OverStretchHandler
+ private var touchSlop = 0f
+ private var minDragDistance = 0
private lateinit var stackScrollerController: NotificationStackScrollLayoutController
private val mTemp2 = IntArray(2)
private var mDraggedFarEnough: Boolean = false
@@ -102,9 +103,7 @@
private var mPulsing: Boolean = false
var isWakingToShadeLocked: Boolean = false
private set
- private var overStretchAmount: Float = 0.0f
- private var mWakeUpHeight: Float = 0.0f
- private var mReachedWakeUpHeight: Boolean = false
+
private var velocityTracker: VelocityTracker? = null
private val isFalseTouch: Boolean
@@ -114,12 +113,21 @@
var bouncerShowing: Boolean = false
init {
- mMinDragDistance = context.resources.getDimensionPixelSize(
- R.dimen.keyguard_drag_down_min_distance)
- mTouchSlop = ViewConfiguration.get(context).scaledTouchSlop.toFloat()
+ initResources(context)
+ configurationController.addCallback(object : ConfigurationController.ConfigurationListener {
+ override fun onConfigChanged(newConfig: Configuration?) {
+ initResources(context)
+ }
+ })
mPowerManager = context.getSystemService(PowerManager::class.java)
}
+ private fun initResources(context: Context) {
+ minDragDistance = context.resources.getDimensionPixelSize(
+ R.dimen.keyguard_drag_down_min_distance)
+ touchSlop = ViewConfiguration.get(context).scaledTouchSlop.toFloat()
+ }
+
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
return canHandleMotionEvent() && startExpansion(event)
}
@@ -148,14 +156,12 @@
MotionEvent.ACTION_MOVE -> {
val h = y - mInitialTouchY
- if (h > mTouchSlop && h > Math.abs(x - mInitialTouchX)) {
+ if (h > touchSlop && h > Math.abs(x - mInitialTouchX)) {
falsingCollector.onStartExpandingFromPulse()
isExpanding = true
captureStartingChild(mInitialTouchX, mInitialTouchY)
mInitialTouchY = y
mInitialTouchX = x
- mWakeUpHeight = wakeUpCoordinator.getWakeUpHeight()
- mReachedWakeUpHeight = false
return true
}
}
@@ -216,7 +222,6 @@
}
private fun finishExpansion() {
- resetClock()
val startingChild = mStartingChild
if (mStartingChild != null) {
setUserLocked(mStartingChild!!, false)
@@ -230,6 +235,7 @@
}
lockscreenShadeTransitionController.goToLockedShade(startingChild,
needsQSAnimation = false)
+ lockscreenShadeTransitionController.finishPulseAnimation(cancelled = false)
leavingLockscreen = true
isExpanding = false
if (mStartingChild is ExpandableNotificationRow) {
@@ -240,24 +246,19 @@
private fun updateExpansionHeight(height: Float) {
var expansionHeight = max(height, 0.0f)
- if (!mReachedWakeUpHeight && height > mWakeUpHeight) {
- mReachedWakeUpHeight = true
- }
if (mStartingChild != null) {
val child = mStartingChild!!
val newHeight = Math.min((child.collapsedHeight + expansionHeight).toInt(),
child.maxContentHeight)
child.actualHeight = newHeight
- expansionHeight = max(newHeight.toFloat(), expansionHeight)
} else {
- val target = if (mReachedWakeUpHeight) mWakeUpHeight else 0.0f
- wakeUpCoordinator.setNotificationsVisibleForExpansion(height > target,
- true /* animate */,
- true /* increaseSpeed */)
- expansionHeight = max(mWakeUpHeight, expansionHeight)
+ wakeUpCoordinator.setNotificationsVisibleForExpansion(
+ height
+ > lockscreenShadeTransitionController.distanceUntilShowingPulsingNotifications,
+ true /* animate */,
+ true /* increaseSpeed */)
}
- val dragDownAmount = wakeUpCoordinator.setPulseHeight(expansionHeight)
- setOverStretchAmount(dragDownAmount)
+ lockscreenShadeTransitionController.setPulseHeight(expansionHeight, animate = false)
}
private fun captureStartingChild(x: Float, y: Float) {
@@ -269,11 +270,6 @@
}
}
- private fun setOverStretchAmount(amount: Float) {
- overStretchAmount = amount
- overStretchHandler.setOverStretchAmount(amount)
- }
-
private fun reset(child: ExpandableView) {
if (child.actualHeight == child.collapsedHeight) {
setUserLocked(child, false)
@@ -297,25 +293,14 @@
}
}
- private fun resetClock() {
- val anim = ValueAnimator.ofFloat(overStretchAmount, 0f)
- anim.interpolator = Interpolators.FAST_OUT_SLOW_IN
- anim.duration = SPRING_BACK_ANIMATION_LENGTH_MS.toLong()
- anim.addUpdateListener {
- animation -> setOverStretchAmount(animation.animatedValue as Float)
- }
- anim.start()
- }
-
private fun cancelExpansion() {
isExpanding = false
falsingCollector.onExpansionFromPulseStopped()
if (mStartingChild != null) {
reset(mStartingChild!!)
mStartingChild = null
- } else {
- resetClock()
}
+ lockscreenShadeTransitionController.finishPulseAnimation(cancelled = true)
wakeUpCoordinator.setNotificationsVisibleForExpansion(false /* visible */,
true /* animate */,
false /* increaseSpeed */)
@@ -333,11 +318,7 @@
} else null
}
- fun setUp(
- stackScrollerController: NotificationStackScrollLayoutController,
- overStrechHandler: OverStretchHandler
- ) {
- this.overStretchHandler = overStrechHandler
+ fun setUp(stackScrollerController: NotificationStackScrollLayoutController) {
this.stackScrollerController = stackScrollerController
}
@@ -348,12 +329,4 @@
fun onStartedWakingUp() {
isWakingToShadeLocked = false
}
-
- interface OverStretchHandler {
-
- /**
- * Set the overstretch amount in pixels This will be rubberbanded later
- */
- fun setOverStretchAmount(amount: Float)
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index 180f81c..83701a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -25,7 +25,6 @@
import android.util.ArrayMap;
import android.util.Pair;
-import com.android.internal.util.Preconditions;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.statusbar.policy.RemoteInputView;
@@ -245,6 +244,10 @@
mCallbacks.add(callback);
}
+ public void removeCallback(Callback callback) {
+ mCallbacks.remove(callback);
+ }
+
public void remoteInputSent(NotificationEntry entry) {
int N = mCallbacks.size();
for (int i = 0; i < N; i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index d4f5bd2..545dca8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -32,7 +32,7 @@
import android.util.FloatProperty;
import android.util.Log;
import android.view.InsetsFlags;
-import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.View;
import android.view.ViewDebug;
import android.view.WindowInsetsController.Appearance;
@@ -434,9 +434,9 @@
@Override
public void setSystemBarAttributes(@Appearance int appearance, @Behavior int behavior,
- InsetsState requestedState, String packageName) {
- boolean isFullscreen = !requestedState.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR)
- || !requestedState.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR);
+ InsetsVisibilities requestedVisibilities, String packageName) {
+ boolean isFullscreen = !requestedVisibilities.getVisibility(ITYPE_STATUS_BAR)
+ || !requestedVisibilities.getVisibility(ITYPE_NAVIGATION_BAR);
if (mIsFullscreen != isFullscreen) {
mIsFullscreen = isFullscreen;
synchronized (mListeners) {
@@ -451,7 +451,7 @@
if (DEBUG_IMMERSIVE_APPS) {
boolean dim = (appearance & APPEARANCE_LOW_PROFILE_BARS) != 0;
String behaviorName = ViewDebug.flagsToString(InsetsFlags.class, "behavior", behavior);
- String requestedVisibilityString = requestedState.toSourceVisibilityString();
+ String requestedVisibilityString = requestedVisibilities.toString();
if (requestedVisibilityString.isEmpty()) {
requestedVisibilityString = "none";
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
index 0bbae2a..f0b2c2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
@@ -19,7 +19,7 @@
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
-import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.View;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
@@ -161,7 +161,7 @@
* Set the system bar attributes
*/
void setSystemBarAttributes(@Appearance int appearance, @Behavior int behavior,
- InsetsState requestedState, String packageName);
+ InsetsVisibilities requestedVisibilities, String packageName);
/**
* Set pulsing
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
index 5f10e55..29cfb07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
@@ -18,6 +18,8 @@
import android.animation.Animator
import android.annotation.UiThread
+import android.graphics.Point
+import android.graphics.Rect
import android.util.Log
import android.view.Gravity
import android.view.View
@@ -31,9 +33,16 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.StatusBarState.SHADE
import com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED
-import com.android.systemui.statusbar.phone.StatusBarLocationPublisher
-import com.android.systemui.statusbar.phone.StatusBarMarginUpdatedListener
+import com.android.systemui.statusbar.phone.StatusBarContentInsetsChangedListener
+import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
+import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.leak.RotationUtils
+import com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE
+import com.android.systemui.util.leak.RotationUtils.ROTATION_NONE
+import com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE
+import com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN
+import com.android.systemui.util.leak.RotationUtils.Rotation
import java.lang.IllegalStateException
import java.util.concurrent.Executor
@@ -58,7 +67,8 @@
class PrivacyDotViewController @Inject constructor(
@Main private val mainExecutor: Executor,
private val stateController: StatusBarStateController,
- private val locationPublisher: StatusBarLocationPublisher,
+ private val configurationController: ConfigurationController,
+ private val contentInsetsProvider: StatusBarContentInsetsProvider,
private val animationScheduler: SystemStatusAnimationScheduler
) {
private var sbHeightPortrait = 0
@@ -84,18 +94,27 @@
// Privacy dots are created in ScreenDecoration's UiThread, which is not the main thread
private var uiExecutor: DelayableExecutor? = null
- private val marginListener: StatusBarMarginUpdatedListener =
- object : StatusBarMarginUpdatedListener {
- override fun onStatusBarMarginUpdated(marginLeft: Int, marginRight: Int) {
- setStatusBarMargins(marginLeft, marginRight)
- }
- }
-
private val views: Sequence<View>
get() = if (!this::tl.isInitialized) sequenceOf() else sequenceOf(tl, tr, br, bl)
init {
- locationPublisher.addCallback(marginListener)
+ contentInsetsProvider.addCallback(object : StatusBarContentInsetsChangedListener {
+ override fun onStatusBarContentInsetsChanged() {
+ dlog("onStatusBarContentInsetsChanged: ")
+ setNewLayoutRects()
+ }
+ })
+ configurationController.addCallback(object : ConfigurationController.ConfigurationListener {
+ override fun onLayoutDirectionChanged(isRtl: Boolean) {
+ synchronized(this) {
+ val corner = selectDesignatedCorner(nextViewState.rotation, isRtl)
+ nextViewState = nextViewState.copy(
+ layoutRtl = isRtl,
+ designatedCorner = corner
+ )
+ }
+ }
+ })
stateController.addCallback(object : StatusBarStateController.StateListener {
override fun onExpandedChanged(isExpanded: Boolean) {
@@ -123,16 +142,19 @@
fun setNewRotation(rot: Int) {
dlog("updateRotation: $rot")
+ val isRtl: Boolean
synchronized(lock) {
if (rot == nextViewState.rotation) {
return
}
+
+ isRtl = nextViewState.layoutRtl
}
// If we rotated, hide all dotes until the next state resolves
setCornerVisibilities(View.INVISIBLE)
- val newCorner = selectDesignatedCorner(rot)
+ val newCorner = selectDesignatedCorner(rot, isRtl)
val index = newCorner.cornerIndex()
val h = when (rot) {
@@ -222,15 +244,77 @@
}
}
+ @UiThread
+ private fun setCornerSizes(state: ViewState) {
+ // StatusBarContentInsetsProvider can tell us the location of the privacy indicator dot
+ // in every rotation. The only thing we need to check is rtl
+ val rtl = state.layoutRtl
+ val size = Point()
+ tl.context.display.getRealSize(size)
+ val currentRotation = RotationUtils.getExactRotation(tl.context)
+
+ val displayWidth: Int
+ val displayHeight: Int
+ if (currentRotation == ROTATION_LANDSCAPE || currentRotation == ROTATION_SEASCAPE) {
+ displayWidth = size.y
+ displayHeight = size.x
+ } else {
+ displayWidth = size.x
+ displayHeight = size.y
+ }
+
+ var rot = activeRotationForCorner(tl, rtl)
+ var contentInsets = state.contentRectForRotation(rot)
+ (tl.layoutParams as FrameLayout.LayoutParams).apply {
+ height = contentInsets.height()
+ if (rtl) {
+ width = contentInsets.left
+ } else {
+ width = displayHeight - contentInsets.right
+ }
+ }
+
+ rot = activeRotationForCorner(tr, rtl)
+ contentInsets = state.contentRectForRotation(rot)
+ (tr.layoutParams as FrameLayout.LayoutParams).apply {
+ height = contentInsets.height()
+ if (rtl) {
+ width = contentInsets.left
+ } else {
+ width = displayWidth - contentInsets.right
+ }
+ }
+
+ rot = activeRotationForCorner(br, rtl)
+ contentInsets = state.contentRectForRotation(rot)
+ (br.layoutParams as FrameLayout.LayoutParams).apply {
+ height = contentInsets.height()
+ if (rtl) {
+ width = contentInsets.left
+ } else {
+ width = displayHeight - contentInsets.right
+ }
+ }
+
+ rot = activeRotationForCorner(bl, rtl)
+ contentInsets = state.contentRectForRotation(rot)
+ (bl.layoutParams as FrameLayout.LayoutParams).apply {
+ height = contentInsets.height()
+ if (rtl) {
+ width = contentInsets.left
+ } else {
+ width = displayWidth - contentInsets.right
+ }
+ }
+ }
+
// Designated view will be the one at statusbar's view.END
@UiThread
- private fun selectDesignatedCorner(r: Int): View? {
+ private fun selectDesignatedCorner(r: Int, isRtl: Boolean): View? {
if (!this::tl.isInitialized) {
return null
}
- val isRtl = tl.isLayoutRtl
-
return when (r) {
0 -> if (isRtl) tl else tr
1 -> if (isRtl) tr else br
@@ -282,6 +366,17 @@
return modded
}
+ @Rotation
+ private fun activeRotationForCorner(corner: View, rtl: Boolean): Int {
+ // Each corner will only be visible in a single rotation, based on rtl
+ return when (corner) {
+ tr -> if (rtl) ROTATION_LANDSCAPE else ROTATION_NONE
+ tl -> if (rtl) ROTATION_NONE else ROTATION_SEASCAPE
+ br -> if (rtl) ROTATION_UPSIDE_DOWN else ROTATION_LANDSCAPE
+ else /* bl */ -> if (rtl) ROTATION_SEASCAPE else ROTATION_UPSIDE_DOWN
+ }
+ }
+
private fun widthForCorner(corner: Int, left: Int, right: Int): Int {
return when (corner) {
TOP_LEFT, BOTTOM_LEFT -> left
@@ -303,15 +398,32 @@
bl = bottomLeft
br = bottomRight
- val dc = selectDesignatedCorner(0)
+ val rtl = configurationController.isLayoutRtl
+ val dc = selectDesignatedCorner(0, rtl)
+
val index = dc.cornerIndex()
mainExecutor.execute {
animationScheduler.addCallback(systemStatusAnimationCallback)
}
+ val left = contentInsetsProvider.getStatusBarContentInsetsForRotation(ROTATION_SEASCAPE)
+ val top = contentInsetsProvider.getStatusBarContentInsetsForRotation(ROTATION_NONE)
+ val right = contentInsetsProvider.getStatusBarContentInsetsForRotation(ROTATION_LANDSCAPE)
+ val bottom = contentInsetsProvider
+ .getStatusBarContentInsetsForRotation(ROTATION_UPSIDE_DOWN)
+
synchronized(lock) {
- nextViewState = nextViewState.copy(designatedCorner = dc, cornerIndex = index)
+ nextViewState = nextViewState.copy(
+ viewInitialized = true,
+ designatedCorner = dc,
+ cornerIndex = index,
+ seascapeRect = left,
+ portraitRect = top,
+ landscapeRect = right,
+ upsideDownRect = bottom,
+ layoutRtl = rtl
+ )
}
}
@@ -324,19 +436,6 @@
sbHeightLandscape = 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
- */
- private fun setStatusBarMargins(left: Int, right: Int) {
- dlog("setStatusBarMargins l=$left r=$right")
- synchronized(lock) {
- nextViewState = nextViewState.copy(marginLeft = left, marginRight = right)
- }
- }
-
private fun updateStatusBarState() {
synchronized(lock) {
nextViewState = nextViewState.copy(shadeExpanded = isShadeInQs())
@@ -377,6 +476,11 @@
@UiThread
private fun resolveState(state: ViewState) {
dlog("resolveState $state")
+ if (!state.viewInitialized) {
+ dlog("resolveState: view is not initialized. skipping.")
+ return
+ }
+
if (state == currentViewState) {
dlog("resolveState: skipping")
return
@@ -387,23 +491,15 @@
updateRotations(state.rotation)
}
- if (state.height != currentViewState.height) {
- updateHeights(state.rotation)
- }
-
- if (state.marginLeft != currentViewState.marginLeft ||
- state.marginRight != currentViewState.marginRight) {
- updateCornerSizes(state.marginLeft, state.marginRight, state.rotation)
+ if (state.needsLayout(currentViewState)) {
+ setCornerSizes(state)
+ views.forEach { it.requestLayout() }
}
if (state.designatedCorner != currentViewState.designatedCorner) {
updateDesignatedCorner(state.designatedCorner, state.shouldShowDot())
}
- if (state.needsLayout(currentViewState)) {
- views.forEach { it.requestLayout() }
- }
-
val shouldShow = state.shouldShowDot()
if (shouldShow != currentViewState.shouldShowDot()) {
if (shouldShow && state.designatedCorner != null) {
@@ -441,6 +537,30 @@
}
return -1
}
+
+ // Returns [left, top, right, bottom] aka [seascape, none, landscape, upside-down]
+ private fun getLayoutRects(): List<Rect> {
+ val left = contentInsetsProvider.getStatusBarContentInsetsForRotation(ROTATION_SEASCAPE)
+ val top = contentInsetsProvider.getStatusBarContentInsetsForRotation(ROTATION_NONE)
+ val right = contentInsetsProvider.getStatusBarContentInsetsForRotation(ROTATION_LANDSCAPE)
+ val bottom = contentInsetsProvider
+ .getStatusBarContentInsetsForRotation(ROTATION_UPSIDE_DOWN)
+
+ return listOf(left, top, right, bottom)
+ }
+
+ private fun setNewLayoutRects() {
+ val rects = getLayoutRects()
+
+ synchronized(lock) {
+ nextViewState = nextViewState.copy(
+ seascapeRect = rects[0],
+ portraitRect = rects[1],
+ landscapeRect = rects[2],
+ upsideDownRect = rects[3]
+ )
+ }
+ }
}
private fun dlog(s: String) {
@@ -461,7 +581,7 @@
const val BOTTOM_LEFT = 3
private const val DURATION = 160L
private const val TAG = "PrivacyDotViewController"
-private const val DEBUG = true
+private const val DEBUG = false
private const val DEBUG_VERBOSE = false
private fun Int.toGravity(): Int {
@@ -485,14 +605,20 @@
}
private data class ViewState(
+ val viewInitialized: Boolean = false,
+
val systemPrivacyEventIsActive: Boolean = false,
val shadeExpanded: Boolean = false,
val qsExpanded: Boolean = false,
+ val portraitRect: Rect? = null,
+ val landscapeRect: Rect? = null,
+ val upsideDownRect: Rect? = null,
+ val seascapeRect: Rect? = null,
+ val layoutRtl: Boolean = false,
+
val rotation: Int = 0,
val height: Int = 0,
- val marginLeft: Int = 0,
- val marginRight: Int = 0,
val cornerIndex: Int = -1,
val designatedCorner: View? = null
) {
@@ -502,7 +628,20 @@
fun needsLayout(other: ViewState): Boolean {
return rotation != other.rotation ||
- marginRight != other.marginRight ||
- height != other.height
+ layoutRtl != other.layoutRtl ||
+ portraitRect != other.portraitRect ||
+ landscapeRect != other.landscapeRect ||
+ upsideDownRect != other.upsideDownRect ||
+ seascapeRect != other.seascapeRect
+ }
+
+ fun contentRectForRotation(@Rotation rot: Int): Rect {
+ return when (rot) {
+ ROTATION_NONE -> portraitRect!!
+ ROTATION_LANDSCAPE -> landscapeRect!!
+ ROTATION_UPSIDE_DOWN -> upsideDownRect!!
+ ROTATION_SEASCAPE -> seascapeRect!!
+ else -> throw IllegalArgumentException("not a rotation ($rot)")
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index b0a7767..a2c9ffc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -374,10 +374,6 @@
}
}
- fun getWakeUpHeight(): Float {
- return mStackScrollerController.wakeUpHeight
- }
-
private fun updateHideAmount() {
val linearAmount = min(1.0f - mLinearVisibilityAmount, mLinearDozeAmount)
val amount = min(1.0f - mVisibilityAmount, mDozeAmount)
@@ -395,16 +391,6 @@
}
}
- /**
- * Set the height how tall notifications are pulsing. This is only set whenever we are expanding
- * from a pulse and determines how much the notifications are expanded.
- */
- fun setPulseHeight(height: Float): Float {
- val overflow = mStackScrollerController.setPulseHeight(height)
- // no overflow for the bypass experience
- return if (bypassController.bypassEnabled) 0.0f else overflow
- }
-
override fun onHeadsUpStateChanged(entry: NotificationEntry, isHeadsUp: Boolean) {
var animate = shouldAnimateVisibility()
if (!isHeadsUp) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
index be1383f..6e98c27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
@@ -149,7 +149,7 @@
final String entryKey = entry.getKey();
if (mHeadsUpManager.isAlerting(entryKey)) {
boolean removeImmediatelyForRemoteInput =
- mRemoteInputManager.getController().isSpinning(entryKey)
+ mRemoteInputManager.isSpinning(entryKey)
&& !FORCE_REMOTE_INPUT_HISTORY;
mHeadsUpManager.removeNotification(entry.getKey(), removeImmediatelyForRemoteInput);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpController.java
index 4d56e60..b1c69e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpController.java
@@ -152,7 +152,7 @@
// Also we should not defer the removal if reordering isn't allowed since otherwise
// some notifications can't disappear before the panel is closed.
boolean ignoreEarliestRemovalTime =
- mRemoteInputManager.getController().isSpinning(key)
+ mRemoteInputManager.isSpinning(key)
&& !FORCE_REMOTE_INPUT_HISTORY
|| !mVisualStabilityManager.isReorderingAllowed();
mHeadsUpManager.removeNotification(key, ignoreEarliestRemovalTime);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 93166f3..73bb6cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -287,7 +287,7 @@
mGroupExpansionChanging = true;
final boolean wasExpanded = mGroupExpansionManager.isGroupExpanded(mEntry);
boolean nowExpanded = mGroupExpansionManager.toggleGroupExpansion(mEntry);
- mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
+ mOnExpandClickListener.onExpandClicked(mEntry, v, nowExpanded);
MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
nowExpanded);
onExpansionChanged(true /* userAction */, wasExpanded);
@@ -310,7 +310,7 @@
setUserExpanded(nowExpanded);
}
notifyHeightChanged(true);
- mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
+ mOnExpandClickListener.onExpandClicked(mEntry, v, nowExpanded);
MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
nowExpanded);
}
@@ -3064,7 +3064,7 @@
}
public interface OnExpandClickListener {
- void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded);
+ void onExpandClicked(NotificationEntry clickedEntry, View clickedView, boolean nowExpanded);
}
@Override
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 085b5a9..2033adf 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
@@ -81,10 +81,9 @@
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.EmptyShadeView;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationShelfController;
-import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.ExpandAnimationParameters;
import com.android.systemui.statusbar.notification.FakeShadowView;
@@ -440,7 +439,6 @@
private final Rect mTmpRect = new Rect();
private DismissListener mDismissListener;
private DismissAllAnimationListener mDismissAllAnimationListener;
- private NotificationRemoteInputManager mRemoteInputManager;
private ShadeController mShadeController;
private Consumer<Boolean> mOnStackYChanged;
@@ -455,6 +453,7 @@
private float mLastSentExpandedHeight;
private boolean mWillExpand;
private int mGapHeight;
+ private boolean mIsRemoteInputActive;
/**
* The extra inset during the full shade transition
@@ -676,6 +675,10 @@
mSectionsManager.reinflateViews(LayoutInflater.from(mContext));
}
+ public void setIsRemoteInputActive(boolean isActive) {
+ mIsRemoteInputActive = isActive;
+ }
+
@VisibleForTesting
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void updateFooter() {
@@ -685,11 +688,10 @@
// TODO: move this logic to controller, which will invoke updateFooterView directly
boolean showDismissView = mClearAllEnabled &&
mController.hasActiveClearableNotifications(ROWS_ALL);
- RemoteInputController remoteInputController = mRemoteInputManager.getController();
boolean showFooterView = (showDismissView || getVisibleNotificationCount() > 0)
&& mStatusBarState != StatusBarState.KEYGUARD
&& !mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying()
- && (remoteInputController == null || !remoteInputController.isRemoteInputActive());
+ && !mIsRemoteInputActive;
boolean showHistory = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, UserHandle.USER_CURRENT) == 1;
@@ -5142,12 +5144,17 @@
* @return the overflow how much the height is further than he lowest notification
*/
public float setPulseHeight(float height) {
+ float overflow;
mAmbientState.setPulseHeight(height);
if (mKeyguardBypassEnabled) {
notifyAppearChangedListeners();
+ overflow = Math.max(0, height - getIntrinsicPadding());
+ } else {
+ overflow = Math.max(0, height
+ - mAmbientState.getInnerHeight(true /* ignorePulseHeight */));
}
requestChildrenUpdate();
- return Math.max(0, height - mAmbientState.getInnerHeight(true /* ignorePulseHeight */));
+ return overflow;
}
public float getPulseHeight() {
@@ -5207,12 +5214,9 @@
public float calculateAppearFractionBypass() {
float pulseHeight = getPulseHeight();
- float wakeUpHeight = getWakeUpHeight();
- float dragDownAmount = pulseHeight - wakeUpHeight;
-
// The total distance required to fully reveal the header
float totalDistance = getIntrinsicPadding();
- return MathUtils.smoothStep(0, totalDistance, dragDownAmount);
+ return MathUtils.smoothStep(0, totalDistance, pulseHeight);
}
public void setController(
@@ -5344,10 +5348,6 @@
mFooterDismissListener = listener;
}
- public void setRemoteInputManager(NotificationRemoteInputManager remoteInputManager) {
- mRemoteInputManager = remoteInputManager;
- }
-
void setShadeController(ShadeController shadeController) {
mShadeController = shadeController;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 428a840..a160e10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -682,7 +682,13 @@
NotificationPanelEvent.fromSelection(selection)));
mView.setFooterDismissListener(() ->
mMetricsLogger.action(MetricsEvent.ACTION_DISMISS_ALL_NOTES));
- mView.setRemoteInputManager(mRemoteInputManager);
+ mView.setIsRemoteInputActive(mRemoteInputManager.isRemoteInputActive());
+ mRemoteInputManager.addControllerCallback(new RemoteInputController.Callback() {
+ @Override
+ public void onRemoteInputActive(boolean active) {
+ mView.setIsRemoteInputActive(active);
+ }
+ });
mView.setShadeController(mShadeController);
if (mFgFeatureController.isForegroundServiceDismissalEnabled()) {
@@ -897,10 +903,6 @@
mView.setDozeAmount(amount);
}
- public float getWakeUpHeight() {
- return mView.getWakeUpHeight();
- }
-
public int getSpeedBumpIndex() {
return mView.getSpeedBumpIndex();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index cbcccbe..b36dc56 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -399,7 +399,8 @@
ambientState.getExpansionFraction(), true /* notification */);
}
- if (view.mustStayOnScreen() && viewState.yTranslation >= 0) {
+ if (ambientState.isShadeExpanded() && view.mustStayOnScreen()
+ && viewState.yTranslation >= 0) {
// Even if we're not scrolled away we're in view and we're also not in the
// shelf. We can relax the constraints and let us scroll off the top!
float end = viewState.yTranslation + viewState.height + ambientState.getStackY();
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 a68dab9..00341b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -37,7 +37,6 @@
import android.view.ViewStub;
import android.widget.LinearLayout;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -79,9 +78,9 @@
public static final int FADE_IN_DURATION = 320;
public static final int FADE_IN_DELAY = 50;
private PhoneStatusBarView mStatusBar;
- private StatusBarStateController mStatusBarStateController;
- private KeyguardStateController mKeyguardStateController;
- private NetworkController mNetworkController;
+ private final StatusBarStateController mStatusBarStateController;
+ private final KeyguardStateController mKeyguardStateController;
+ private final NetworkController mNetworkController;
private LinearLayout mSystemIconArea;
private View mClockView;
private View mOngoingCallChip;
@@ -92,12 +91,13 @@
private Lazy<Optional<StatusBar>> mStatusBarOptionalLazy;
private DarkIconManager mDarkIconManager;
private View mOperatorNameFrame;
- private CommandQueue mCommandQueue;
- private OngoingCallController mOngoingCallController;
+ private final CommandQueue mCommandQueue;
+ private final OngoingCallController mOngoingCallController;
private final SystemStatusAnimationScheduler mAnimationScheduler;
private final StatusBarLocationPublisher mLocationPublisher;
- private NotificationIconAreaController mNotificationIconAreaController;
private final FeatureFlags mFeatureFlags;
+ private final NotificationIconAreaController mNotificationIconAreaController;
+ private final StatusBarIconController mStatusBarIconController;
private List<String> mBlockedIcons = new ArrayList<>();
@@ -122,7 +122,12 @@
StatusBarLocationPublisher locationPublisher,
NotificationIconAreaController notificationIconAreaController,
FeatureFlags featureFlags,
- Lazy<Optional<StatusBar>> statusBarOptionalLazy
+ Lazy<Optional<StatusBar>> statusBarOptionalLazy,
+ StatusBarIconController statusBarIconController,
+ KeyguardStateController keyguardStateController,
+ NetworkController networkController,
+ StatusBarStateController statusBarStateController,
+ CommandQueue commandQueue
) {
mOngoingCallController = ongoingCallController;
mAnimationScheduler = animationScheduler;
@@ -130,15 +135,11 @@
mNotificationIconAreaController = notificationIconAreaController;
mFeatureFlags = featureFlags;
mStatusBarOptionalLazy = statusBarOptionalLazy;
- }
-
- @Override
- public void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mKeyguardStateController = Dependency.get(KeyguardStateController.class);
- mNetworkController = Dependency.get(NetworkController.class);
- mStatusBarStateController = Dependency.get(StatusBarStateController.class);
- mCommandQueue = Dependency.get(CommandQueue.class);
+ mStatusBarIconController = statusBarIconController;
+ mKeyguardStateController = keyguardStateController;
+ mNetworkController = networkController;
+ mStatusBarStateController = statusBarStateController;
+ mCommandQueue = commandQueue;
}
@Override
@@ -164,7 +165,7 @@
mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_alarm_clock));
mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_call_strength));
mDarkIconManager.setBlockList(mBlockedIcons);
- Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
+ mStatusBarIconController.addIconGroup(mDarkIconManager);
mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area);
mClockView = mStatusBar.findViewById(R.id.clock);
mOngoingCallChip = mStatusBar.findViewById(R.id.ongoing_call_chip);
@@ -203,7 +204,8 @@
@Override
public void onDestroyView() {
super.onDestroyView();
- Dependency.get(StatusBarIconController.class).removeIconGroup(mDarkIconManager);
+ mStatusBarIconController.removeIconGroup(mDarkIconManager);
+ mAnimationScheduler.removeCallback(this);
if (mNetworkController.hasEmergencyCryptKeeperText()) {
mNetworkController.removeCallback(mSignalCallback);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
index b148eeb..07618da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
@@ -18,6 +18,7 @@
import android.content.pm.ActivityInfo
import android.content.res.Configuration
import android.os.LocaleList
+import android.view.View.LAYOUT_DIRECTION_RTL
import com.android.systemui.statusbar.policy.ConfigurationController
import java.util.ArrayList
@@ -33,6 +34,7 @@
private var uiMode: Int = 0
private var localeList: LocaleList? = null
private val context: Context
+ private var layoutDirection: Int
init {
val currentConfig = context.resources.configuration
@@ -44,6 +46,7 @@
Configuration.UI_MODE_TYPE_CAR
uiMode = currentConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK
localeList = currentConfig.locales
+ layoutDirection = currentConfig.layoutDirection
}
override fun notifyThemeChanged() {
@@ -101,6 +104,13 @@
}
}
+ if (layoutDirection != newConfig.layoutDirection) {
+ layoutDirection = newConfig.layoutDirection
+ listeners.filterForEach({ this.listeners.contains(it) }) {
+ it.onLayoutDirectionChanged(layoutDirection == LAYOUT_DIRECTION_RTL)
+ }
+ }
+
if (lastConfig.updateFrom(newConfig) and ActivityInfo.CONFIG_ASSETS_PATHS != 0) {
listeners.filterForEach({ this.listeners.contains(it) }) {
it.onOverlayChanged()
@@ -116,6 +126,10 @@
override fun removeCallback(listener: ConfigurationController.ConfigurationListener) {
listeners.remove(listener)
}
+
+ override fun isLayoutRtl(): Boolean {
+ return layoutDirection == LAYOUT_DIRECTION_RTL
+ }
}
// This could be done with a Collection.filter and Collection.forEach, but Collection.filter
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 91d503b..0a4e59c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -19,6 +19,7 @@
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE;
import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_BUTTON;
import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_UNLOCK;
@@ -40,6 +41,7 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
@@ -81,6 +83,11 @@
import com.android.systemui.animation.Interpolators;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.camera.CameraIntents;
+import com.android.systemui.controls.ControlsServiceInfo;
+import com.android.systemui.controls.dagger.ControlsComponent;
+import com.android.systemui.controls.management.ControlsListingController;
+import com.android.systemui.controls.ui.ControlsActivity;
+import com.android.systemui.controls.ui.ControlsUiController;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.IntentButtonProvider;
@@ -98,6 +105,8 @@
import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.android.systemui.wallet.ui.WalletActivity;
+import java.util.List;
+
/**
* Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
* text.
@@ -133,9 +142,12 @@
private KeyguardAffordanceView mLeftAffordanceView;
private ImageView mWalletButton;
+ private ImageView mControlsButton;
private boolean mHasCard = false;
private WalletCardRetriever mCardRetriever = new WalletCardRetriever();
private QuickAccessWalletController mQuickAccessWalletController;
+ private ControlsComponent mControlsComponent;
+ private boolean mControlServicesAvailable = false;
private ViewGroup mIndicationArea;
private TextView mIndicationText;
@@ -188,6 +200,19 @@
private ActivityIntentHelper mActivityIntentHelper;
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private ControlsListingController.ControlsListingCallback mListingCallback =
+ new ControlsListingController.ControlsListingCallback() {
+ public void onServicesUpdated(List<ControlsServiceInfo> serviceInfos) {
+ boolean available = !serviceInfos.isEmpty();
+
+ if (available != mControlServicesAvailable) {
+ mControlServicesAvailable = available;
+ updateControlsVisibility();
+ updateAffordanceColors();
+ }
+ }
+ };
+
public KeyguardBottomAreaView(Context context) {
this(context, null);
}
@@ -253,6 +278,7 @@
mRightAffordanceView = findViewById(R.id.camera_button);
mLeftAffordanceView = findViewById(R.id.left_button);
mWalletButton = findViewById(R.id.wallet_button);
+ mControlsButton = findViewById(R.id.controls_button);
mIndicationArea = findViewById(R.id.keyguard_indication_area);
mIndicationText = findViewById(R.id.keyguard_indication_text);
mIndicationTextBottom = findViewById(R.id.keyguard_indication_text_bottom);
@@ -276,6 +302,7 @@
mIndicationPadding = getResources().getDimensionPixelSize(
R.dimen.keyguard_indication_area_padding);
updateWalletVisibility();
+ updateControlsVisibility();
}
/**
@@ -328,6 +355,11 @@
mQuickAccessWalletController.unregisterWalletChangeObservers(
WALLET_PREFERENCE_CHANGE, DEFAULT_PAYMENT_APP_CHANGE);
}
+
+ if (mControlsComponent != null) {
+ mControlsComponent.getControlsListingController().ifPresent(
+ c -> c.removeCallback(mListingCallback));
+ }
}
private void initAccessibility() {
@@ -369,13 +401,20 @@
updateLeftAffordanceIcon();
lp = mWalletButton.getLayoutParams();
- lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_wallet_width);
- lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_wallet_width);
+ lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width);
+ lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height);
mWalletButton.setLayoutParams(lp);
+ lp = mControlsButton.getLayoutParams();
+ lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width);
+ lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height);
+ mControlsButton.setLayoutParams(lp);
+
mIndicationPadding = getResources().getDimensionPixelSize(
R.dimen.keyguard_indication_area_padding);
+
updateWalletVisibility();
+ updateAffordanceColors();
}
private void updateRightAffordanceIcon() {
@@ -454,22 +493,38 @@
|| !mQuickAccessWalletController.isWalletEnabled()
|| !mHasCard) {
mWalletButton.setVisibility(GONE);
- mIndicationArea.setPadding(0, 0, 0, 0);
- } else {
- Drawable tileIcon = mQuickAccessWalletController.getWalletClient().getTileIcon();
- if (tileIcon != null) {
- mWalletButton.setImageDrawable(tileIcon);
+
+ if (mControlsButton.getVisibility() == GONE) {
+ mIndicationArea.setPadding(0, 0, 0, 0);
}
- mWalletButton.getDrawable().setTint(
- Utils.getColorAttr(
- mContext,
- com.android.internal.R.attr.textColorPrimary).getDefaultColor());
+ } else {
mWalletButton.setVisibility(VISIBLE);
mWalletButton.setOnClickListener(this::onWalletClick);
mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
}
}
+ private void updateControlsVisibility() {
+ if (mControlsComponent == null) return;
+
+ boolean hasFavorites = mControlsComponent.getControlsController()
+ .map(c -> c.getFavorites().size() > 0)
+ .orElse(false);
+ if (mDozing
+ || !hasFavorites
+ || !mControlServicesAvailable
+ || mControlsComponent.getVisibility() != AVAILABLE) {
+ mControlsButton.setVisibility(GONE);
+ if (mWalletButton.getVisibility() == GONE) {
+ mIndicationArea.setPadding(0, 0, 0, 0);
+ }
+ } else {
+ mControlsButton.setVisibility(VISIBLE);
+ mControlsButton.setOnClickListener(this::onControlsClick);
+ mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
+ }
+ }
+
public boolean isLeftVoiceAssist() {
return mLeftIsVoiceAssist;
}
@@ -751,6 +806,9 @@
if (mWalletButton.getVisibility() == View.VISIBLE) {
startFinishDozeAnimationElement(mWalletButton, delay);
}
+ if (mControlsButton.getVisibility() == View.VISIBLE) {
+ startFinishDozeAnimationElement(mControlsButton, delay);
+ }
if (mLeftAffordanceView.getVisibility() == View.VISIBLE) {
startFinishDozeAnimationElement(mLeftAffordanceView, delay);
delay += DOZE_ANIMATION_STAGGER_DELAY;
@@ -824,6 +882,7 @@
updateCameraVisibility();
updateLeftAffordanceIcon();
updateWalletVisibility();
+ updateControlsVisibility();
if (dozing) {
mOverlayContainer.setVisibility(INVISIBLE);
@@ -857,6 +916,7 @@
mRightAffordanceView.setAlpha(alpha);
mIndicationArea.setAlpha(alpha);
mWalletButton.setAlpha(alpha);
+ mControlsButton.setAlpha(alpha);
}
private class DefaultLeftButton implements IntentButton {
@@ -950,6 +1010,32 @@
mQuickAccessWalletController.queryWalletCards(mCardRetriever);
updateWalletVisibility();
+ updateAffordanceColors();
+ }
+
+ private void updateAffordanceColors() {
+ int iconColor = Utils.getColorAttrDefaultColor(
+ mContext,
+ com.android.internal.R.attr.textColorPrimary);
+ mWalletButton.getDrawable().setTint(iconColor);
+ mControlsButton.getDrawable().setTint(iconColor);
+
+ ColorStateList bgColor = Utils.getColorAttr(
+ mContext,
+ com.android.internal.R.attr.colorSurface);
+ mWalletButton.setBackgroundTintList(bgColor);
+ mControlsButton.setBackgroundTintList(bgColor);
+ }
+
+ /**
+ * Initialize controls via the ControlsComponent
+ */
+ public void initControls(ControlsComponent controlsComponent) {
+ mControlsComponent = controlsComponent;
+ mControlsComponent.getControlsListingController().ifPresent(
+ c -> c.addCallback(mListingCallback));
+
+ updateAffordanceColors();
}
private void onWalletClick(View v) {
@@ -974,19 +1060,41 @@
}
}
+ private void onControlsClick(View v) {
+ if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ return;
+ }
+
+ Intent intent = new Intent(mContext, ControlsActivity.class)
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
+ .putExtra(ControlsUiController.EXTRA_ANIMATE, true);
+
+ if (mControlsComponent.getVisibility() == AVAILABLE) {
+ mContext.startActivity(intent);
+ } else {
+ mActivityStarter.postStartActivityDismissingKeyguard(intent, 0 /* delay */);
+ }
+ }
+
private class WalletCardRetriever implements
QuickAccessWalletClient.OnWalletCardsRetrievedCallback {
@Override
public void onWalletCardsRetrieved(@NonNull GetWalletCardsResponse response) {
mHasCard = !response.getWalletCards().isEmpty();
+ Drawable tileIcon = mQuickAccessWalletController.getWalletClient().getTileIcon();
+ if (tileIcon != null) {
+ mWalletButton.setImageDrawable(tileIcon);
+ }
updateWalletVisibility();
+ updateAffordanceColors();
}
@Override
public void onWalletCardRetrievalError(@NonNull GetWalletCardsError error) {
mHasCard = false;
updateWalletVisibility();
+ updateAffordanceColors();
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index ad4213d..f77c052 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -211,7 +211,7 @@
private int getStackScrollerPadding(int clockYPosition) {
if (mBypassEnabled) {
- return mUnlockedStackScrollerPadding;
+ return (int) (mUnlockedStackScrollerPadding + mOverStretchAmount);
} else if (mIsSplitShade) {
return clockYPosition;
} else {
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 e272d27..222ed63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -18,10 +18,7 @@
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;
@@ -46,35 +43,17 @@
import com.android.settingslib.Utils;
import com.android.systemui.BatteryMeterView;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.FeatureFlags;
-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;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-import com.android.systemui.statusbar.policy.UserInfoController;
-import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
-import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
/**
* The header group on Keyguard.
*/
-public class KeyguardStatusBarView extends RelativeLayout implements
- BatteryStateChangeCallback,
- OnUserInfoChangedListener,
- ConfigurationListener,
- SystemStatusAnimationCallback {
+public class KeyguardStatusBarView extends RelativeLayout {
private static final int LAYOUT_NONE = 0;
private static final int LAYOUT_CUTOUT = 1;
@@ -84,30 +63,23 @@
private boolean mShowPercentAvailable;
private boolean mBatteryCharging;
- private boolean mBatteryListening;
private TextView mCarrierLabel;
private ImageView mMultiUserAvatar;
private BatteryMeterView mBatteryView;
private StatusIconContainer mStatusIconContainer;
- private BatteryController mBatteryController;
private boolean mKeyguardUserSwitcherEnabled;
private final UserManager mUserManager;
private int mSystemIconsSwitcherHiddenExpandedMargin;
private int mSystemIconsBaseMargin;
private View mSystemIconsContainer;
- private TintedIconManager mIconManager;
- private List<String> mBlockedIcons = new ArrayList<>();
private View mCutoutSpace;
private ViewGroup mStatusIconArea;
private int mLayoutState = LAYOUT_NONE;
- private SystemStatusAnimationScheduler mAnimationScheduler;
- private FeatureFlags mFeatureFlags;
-
/**
* Draw this many pixels into the left/right side of the cutout to optimally use the space
*/
@@ -141,10 +113,6 @@
mStatusIconContainer = findViewById(R.id.statusIcons);
loadDimens();
- loadBlockList();
- mBatteryController = Dependency.get(BatteryController.class);
- mAnimationScheduler = Dependency.get(SystemStatusAnimationScheduler.class);
- mFeatureFlags = Dependency.get(FeatureFlags.class);
}
@Override
@@ -190,7 +158,7 @@
setLayoutParams(lp);
}
- private void loadDimens() {
+ void loadDimens() {
Resources res = getResources();
mSystemIconsSwitcherHiddenExpandedMargin = res.getDimensionPixelSize(
R.dimen.system_icons_switcher_hidden_expanded_margin);
@@ -204,14 +172,6 @@
R.dimen.rounded_corner_content_padding);
}
- // Set hidden status bar items
- private void loadBlockList() {
- Resources r = getResources();
- mBlockedIcons.add(r.getString(com.android.internal.R.string.status_bar_volume));
- mBlockedIcons.add(r.getString(com.android.internal.R.string.status_bar_alarm_clock));
- mBlockedIcons.add(r.getString(com.android.internal.R.string.status_bar_call_strength));
- }
-
private void updateVisibilities() {
if (mMultiUserAvatar.getParent() != mStatusIconArea
&& !mKeyguardUserSwitcherEnabled) {
@@ -348,59 +308,19 @@
return true;
}
- public void setListening(boolean listening) {
- if (listening == mBatteryListening) {
- return;
- }
- mBatteryListening = listening;
- if (mBatteryListening) {
- mBatteryController.addCallback(this);
- } else {
- mBatteryController.removeCallback(this);
- }
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- UserInfoController userInfoController = Dependency.get(UserInfoController.class);
- userInfoController.addCallback(this);
- userInfoController.reloadUserInfo();
- Dependency.get(ConfigurationController.class).addCallback(this);
- mIconManager = new TintedIconManager(findViewById(R.id.statusIcons), mFeatureFlags);
- mIconManager.setBlockList(mBlockedIcons);
- Dependency.get(StatusBarIconController.class).addIconGroup(mIconManager);
- mAnimationScheduler.addCallback(this);
- onThemeChanged();
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- Dependency.get(UserInfoController.class).removeCallback(this);
- Dependency.get(StatusBarIconController.class).removeIconGroup(mIconManager);
- Dependency.get(ConfigurationController.class).removeCallback(this);
- mAnimationScheduler.removeCallback(this);
- }
-
- @Override
- public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
+ /** Should only be called from {@link KeyguardStatusBarViewController}. */
+ void onUserInfoChanged(Drawable picture) {
mMultiUserAvatar.setImageDrawable(picture);
}
- @Override
- public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+ /** Should only be called from {@link KeyguardStatusBarViewController}. */
+ void onBatteryLevelChanged(boolean charging) {
if (mBatteryCharging != charging) {
mBatteryCharging = charging;
updateVisibilities();
}
}
- @Override
- public void onPowerSaveChanged(boolean isPowerSave) {
- // could not care less
- }
-
public void setKeyguardUserSwitcherEnabled(boolean enabled) {
mKeyguardUserSwitcherEnabled = enabled;
}
@@ -467,28 +387,20 @@
return false;
}
- public void onThemeChanged() {
+ /** Should only be called from {@link KeyguardStatusBarViewController}. */
+ void onThemeChanged(StatusBarIconController.TintedIconManager iconManager) {
mBatteryView.setColorsFromContext(mContext);
- updateIconsAndTextColors();
- // Reload user avatar
- ((UserInfoControllerImpl) Dependency.get(UserInfoController.class))
- .onDensityOrFontScaleChanged();
+ updateIconsAndTextColors(iconManager);
}
- @Override
- public void onDensityOrFontScaleChanged() {
- loadDimens();
- }
-
- @Override
- public void onOverlayChanged() {
+ /** Should only be called from {@link KeyguardStatusBarViewController}. */
+ void onOverlayChanged() {
mCarrierLabel.setTextAppearance(
Utils.getThemeAttr(mContext, com.android.internal.R.attr.textAppearanceSmall));
- onThemeChanged();
mBatteryView.updatePercentView();
}
- private void updateIconsAndTextColors() {
+ private void updateIconsAndTextColors(StatusBarIconController.TintedIconManager iconManager) {
@ColorInt int textColor = Utils.getColorAttrDefaultColor(mContext,
R.attr.wallpaperTextColor);
@ColorInt int iconColor = Utils.getColorStateListDefaultColor(mContext,
@@ -496,8 +408,8 @@
R.color.light_mode_icon_color_single_tone);
float intensity = textColor == Color.WHITE ? 0 : 1;
mCarrierLabel.setTextColor(iconColor);
- if (mIconManager != null) {
- mIconManager.setTint(iconColor);
+ if (iconManager != null) {
+ iconManager.setTint(iconColor);
}
applyDarkness(R.id.battery, mEmptyRect, intensity, iconColor);
@@ -522,10 +434,10 @@
}
}
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ /** Should only be called from {@link KeyguardStatusBarViewController}. */
+ void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("KeyguardStatusBarView:");
pw.println(" mBatteryCharging: " + mBatteryCharging);
- pw.println(" mBatteryListening: " + mBatteryListening);
pw.println(" mLayoutState: " + mLayoutState);
pw.println(" mKeyguardUserSwitcherEnabled: " + mKeyguardUserSwitcherEnabled);
if (mBatteryView != null) {
@@ -533,19 +445,16 @@
}
}
- /** SystemStatusAnimationCallback */
- @Override
- public void onSystemChromeAnimationStart() {
- if (mAnimationScheduler.getAnimationState() == ANIMATING_OUT) {
+ void onSystemChromeAnimationStart(boolean isAnimatingOut) {
+ if (isAnimatingOut) {
mSystemIconsContainer.setVisibility(View.VISIBLE);
mSystemIconsContainer.setAlpha(0f);
}
}
- @Override
- public void onSystemChromeAnimationEnd() {
+ void onSystemChromeAnimationEnd(boolean isAnimatingIn) {
// Make sure the system icons are out of the way
- if (mAnimationScheduler.getAnimationState() == ANIMATING_IN) {
+ if (isAnimatingIn) {
mSystemIconsContainer.setVisibility(View.INVISIBLE);
mSystemIconsContainer.setAlpha(0f);
} else {
@@ -554,9 +463,8 @@
}
}
- @Override
- public void onSystemChromeAnimationUpdate(ValueAnimator anim) {
- mSystemIconsContainer.setAlpha((float) anim.getAnimatedValue());
+ void onSystemChromeAnimationUpdate(float animatedValue) {
+ mSystemIconsContainer.setAlpha(animatedValue);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 377fb92..5d8d36e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -16,20 +16,120 @@
package com.android.systemui.statusbar.phone;
+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.content.res.Resources;
+
+import androidx.annotation.NonNull;
+
import com.android.keyguard.CarrierTextController;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
+import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.util.ViewController;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
import javax.inject.Inject;
/** View Controller for {@link com.android.systemui.statusbar.phone.KeyguardStatusBarView}. */
public class KeyguardStatusBarViewController extends ViewController<KeyguardStatusBarView> {
private final CarrierTextController mCarrierTextController;
+ private final ConfigurationController mConfigurationController;
+ private final SystemStatusAnimationScheduler mAnimationScheduler;
+ private final BatteryController mBatteryController;
+ private final UserInfoController mUserInfoController;
+ private final StatusBarIconController mStatusBarIconController;
+ private final StatusBarIconController.TintedIconManager.Factory mTintedIconManagerFactory;
+
+ private final ConfigurationController.ConfigurationListener mConfigurationListener =
+ new ConfigurationController.ConfigurationListener() {
+ @Override
+ public void onDensityOrFontScaleChanged() {
+ mView.loadDimens();
+ }
+
+ @Override
+ public void onOverlayChanged() {
+ KeyguardStatusBarViewController.this.onThemeChanged();
+ mView.onOverlayChanged();
+ }
+
+ @Override
+ public void onThemeChanged() {
+ KeyguardStatusBarViewController.this.onThemeChanged();
+ }
+ };
+
+ private final SystemStatusAnimationCallback mAnimationCallback =
+ new SystemStatusAnimationCallback() {
+ @Override
+ public void onSystemChromeAnimationStart() {
+ mView.onSystemChromeAnimationStart(
+ mAnimationScheduler.getAnimationState() == ANIMATING_OUT);
+ }
+
+ @Override
+ public void onSystemChromeAnimationEnd() {
+ mView.onSystemChromeAnimationEnd(
+ mAnimationScheduler.getAnimationState() == ANIMATING_IN);
+ }
+
+ @Override
+ public void onSystemChromeAnimationUpdate(@NonNull ValueAnimator anim) {
+ mView.onSystemChromeAnimationUpdate((float) anim.getAnimatedValue());
+ }
+ };
+
+ private final BatteryController.BatteryStateChangeCallback mBatteryStateChangeCallback =
+ new BatteryController.BatteryStateChangeCallback() {
+ @Override
+ public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+ mView.onBatteryLevelChanged(charging);
+ }
+ };
+
+ private final UserInfoController.OnUserInfoChangedListener mOnUserInfoChangedListener =
+ (name, picture, userAccount) -> mView.onUserInfoChanged(picture);
+
+ private final List<String> mBlockedIcons;
+
+ private boolean mBatteryListening;
+ private StatusBarIconController.TintedIconManager mTintedIconManager;
@Inject
public KeyguardStatusBarViewController(
- KeyguardStatusBarView view, CarrierTextController carrierTextController) {
+ KeyguardStatusBarView view,
+ CarrierTextController carrierTextController,
+ ConfigurationController configurationController,
+ SystemStatusAnimationScheduler animationScheduler,
+ BatteryController batteryController,
+ UserInfoController userInfoController,
+ StatusBarIconController statusBarIconController,
+ StatusBarIconController.TintedIconManager.Factory tintedIconManagerFactory) {
super(view);
mCarrierTextController = carrierTextController;
+ mConfigurationController = configurationController;
+ mAnimationScheduler = animationScheduler;
+ mBatteryController = batteryController;
+ mUserInfoController = userInfoController;
+ mStatusBarIconController = statusBarIconController;
+ mTintedIconManagerFactory = tintedIconManagerFactory;
+
+ Resources r = getResources();
+ mBlockedIcons = Collections.unmodifiableList(Arrays.asList(
+ r.getString(com.android.internal.R.string.status_bar_volume),
+ r.getString(com.android.internal.R.string.status_bar_alarm_clock),
+ r.getString(com.android.internal.R.string.status_bar_call_strength)));
}
@Override
@@ -40,9 +140,55 @@
@Override
protected void onViewAttached() {
+ mConfigurationController.addCallback(mConfigurationListener);
+ mAnimationScheduler.addCallback(mAnimationCallback);
+ mUserInfoController.addCallback(mOnUserInfoChangedListener);
+ if (mTintedIconManager == null) {
+ mTintedIconManager =
+ mTintedIconManagerFactory.create(mView.findViewById(R.id.statusIcons));
+ mTintedIconManager.setBlockList(mBlockedIcons);
+ mStatusBarIconController.addIconGroup(mTintedIconManager);
+ }
+ onThemeChanged();
}
@Override
protected void onViewDetached() {
+ // Don't receive future #onViewAttached calls so that we don't accidentally have two
+ // controllers registered for the same view.
+ // TODO(b/194181195): This shouldn't be necessary.
+ destroy();
+
+ mConfigurationController.removeCallback(mConfigurationListener);
+ mAnimationScheduler.removeCallback(mAnimationCallback);
+ mUserInfoController.removeCallback(mOnUserInfoChangedListener);
+ if (mTintedIconManager != null) {
+ mStatusBarIconController.removeIconGroup(mTintedIconManager);
+ }
+ }
+
+ /** Should be called when the theme changes. */
+ public void onThemeChanged() {
+ mView.onThemeChanged(mTintedIconManager);
+ }
+
+ /** Sets whether this controller should listen to battery updates. */
+ public void setBatteryListening(boolean listening) {
+ if (listening == mBatteryListening) {
+ return;
+ }
+ mBatteryListening = listening;
+ if (mBatteryListening) {
+ mBatteryController.addCallback(mBatteryStateChangeCallback);
+ } else {
+ mBatteryController.removeCallback(mBatteryStateChangeCallback);
+ }
+ }
+
+ /** */
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("KeyguardStatusBarView:");
+ pw.println(" mBatteryListening: " + mBatteryListening);
+ mView.dump(fd, pw, args);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
index c213707..3f33281 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
@@ -21,7 +21,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.Nullable;
-import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.View;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
@@ -150,7 +150,8 @@
@Override
public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, InsetsState requestedState, String packageName) {
+ @Behavior int behavior, InsetsVisibilities requestedVisibilities,
+ String packageName) {
if (displayId != mDisplayId) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index cfe95e0..6516abd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -165,14 +165,14 @@
* Called by the Keyguard*ViewController whose view contains the aod icons.
*/
public void setupAodIcons(@NonNull NotificationIconContainer aodIcons) {
- boolean changed = mAodIcons != null;
+ boolean changed = mAodIcons != null && aodIcons != mAodIcons;
if (changed) {
mAodIcons.setAnimationsEnabled(false);
mAodIcons.removeAllViews();
}
mAodIcons = aodIcons;
mAodIcons.setOnLockScreen(true);
- updateAodIconsVisibility(false /* animate */);
+ updateAodIconsVisibility(false /* animate */, changed);
updateAnimations();
if (changed) {
updateAodNotificationIcons();
@@ -587,7 +587,7 @@
@Override
public void onStateChanged(int newState) {
- updateAodIconsVisibility(false /* animate */);
+ updateAodIconsVisibility(false /* animate */, false /* force */);
updateAnimations();
}
@@ -663,18 +663,18 @@
// since otherwise the unhide animation overlaps
animate &= fullyHidden;
}
- updateAodIconsVisibility(animate);
+ updateAodIconsVisibility(animate, false /* force */);
updateAodNotificationIcons();
}
@Override
public void onPulseExpansionChanged(boolean expandingChanged) {
if (expandingChanged) {
- updateAodIconsVisibility(true /* animate */);
+ updateAodIconsVisibility(true /* animate */, false /* force */);
}
}
- private void updateAodIconsVisibility(boolean animate) {
+ private void updateAodIconsVisibility(boolean animate, boolean forceUpdate) {
if (mAodIcons == null) {
return;
}
@@ -688,10 +688,11 @@
&& !mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying()) {
visible = false;
}
- if (visible && mWakeUpCoordinator.isPulseExpanding()) {
+ if (visible && mWakeUpCoordinator.isPulseExpanding()
+ && !mBypassController.getBypassEnabled()) {
visible = false;
}
- if (mAodIconsVisible != visible) {
+ if (mAodIconsVisible != visible || forceUpdate) {
mAodIconsVisible = visible;
mAodIcons.animate().cancel();
if (animate) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index ade9eb5..b8995f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -104,6 +104,7 @@
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.controls.dagger.ControlsComponent;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeLog;
@@ -326,6 +327,7 @@
private final ScrimController mScrimController;
private final PrivacyDotViewController mPrivacyDotViewController;
private final QuickAccessWalletController mQuickAccessWalletController;
+ private final ControlsComponent mControlsComponent;
private final NotificationRemoteInputManager mRemoteInputManager;
// Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow card.
@@ -344,7 +346,7 @@
private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController;
private KeyguardUserSwitcherController mKeyguardUserSwitcherController;
private KeyguardStatusBarView mKeyguardStatusBar;
- private KeyguardStatusBarViewController mKeyguarStatusBarViewController;
+ private KeyguardStatusBarViewController mKeyguardStatusBarViewController;
private ViewGroup mBigClockContainer;
@VisibleForTesting QS mQs;
private FrameLayout mQsFrame;
@@ -612,6 +614,11 @@
* Is the current animator resetting the qs translation.
*/
private boolean mIsQsTranslationResetAnimator;
+
+ /**
+ * Is the current animator resetting the pulse expansion after a drag down
+ */
+ private boolean mIsPulseExpansionResetAnimator;
private final Rect mKeyguardStatusAreaClipBounds = new Rect();
private final Region mQsInterceptRegion = new Region();
@@ -725,7 +732,8 @@
SecureSettings secureSettings,
SplitShadeHeaderController splitShadeHeaderController,
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
- NotificationRemoteInputManager remoteInputManager) {
+ NotificationRemoteInputManager remoteInputManager,
+ ControlsComponent controlsComponent) {
super(view, falsingManager, dozeLog, keyguardStateController,
(SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
statusBarKeyguardViewManager, latencyTracker, flingAnimationUtilsBuilder.get(),
@@ -735,6 +743,7 @@
mKeyguardMediaController = keyguardMediaController;
mPrivacyDotViewController = privacyDotViewController;
mQuickAccessWalletController = quickAccessWalletController;
+ mControlsComponent = controlsComponent;
mMetricsLogger = metricsLogger;
mActivityManager = activityManager;
mConfigurationController = configurationController;
@@ -888,14 +897,7 @@
mWakeUpCoordinator.setStackScroller(mNotificationStackScrollLayoutController);
mQsFrame = mView.findViewById(R.id.qs_frame);
- mPulseExpansionHandler.setUp(mNotificationStackScrollLayoutController,
- amount -> {
- float progress = amount / mView.getHeight();
- float overstretch = Interpolators.getOvershootInterpolation(progress,
- (float) mMaxOverscrollAmountForPulse / mView.getHeight(),
- 0.2f);
- setOverStrechAmount(overstretch);
- });
+ mPulseExpansionHandler.setUp(mNotificationStackScrollLayoutController);
mWakeUpCoordinator.addListener(new NotificationWakeUpCoordinator.WakeUpListener() {
@Override
public void onFullyHiddenChanged(boolean isFullyHidden) {
@@ -907,7 +909,6 @@
if (mKeyguardBypassController.getBypassEnabled()) {
// Position the notifications while dragging down while pulsing
requestScrollerTopPaddingUpdate(false /* animate */);
- updateQSPulseExpansion();
}
}
});
@@ -974,9 +975,13 @@
KeyguardStatusBarViewComponent statusBarViewComponent =
mKeyguardStatusBarViewComponentFactory.build(keyguardStatusBarView);
- mKeyguarStatusBarViewController =
+ if (mKeyguardStatusBarViewController != null) {
+ // TODO(b/194181195): This shouldn't be necessary.
+ mKeyguardStatusBarViewController.onViewDetached();
+ }
+ mKeyguardStatusBarViewController =
statusBarViewComponent.getKeyguardStatusBarViewController();
- mKeyguarStatusBarViewController.init();
+ mKeyguardStatusBarViewController.init();
if (mKeyguardUserSwitcherController != null) {
// Try to close the switcher so that callbacks are triggered if necessary.
@@ -1153,10 +1158,6 @@
mStatusBarStateListener.onDozeAmountChanged(mStatusBarStateController.getDozeAmount(),
mStatusBarStateController.getInterpolatedDozeAmount());
- if (mKeyguardStatusBar != null) {
- mKeyguardStatusBar.onThemeChanged();
- }
-
mKeyguardStatusViewController.setKeyguardStatusViewVisibility(
mBarState,
false,
@@ -1191,6 +1192,7 @@
mKeyguardBottomArea.setUserSetupComplete(mUserSetupComplete);
mKeyguardBottomArea.setFalsingManager(mFalsingManager);
mKeyguardBottomArea.initWallet(mQuickAccessWalletController);
+ mKeyguardBottomArea.initControls(mControlsComponent);
}
private void updateMaxDisplayedNotifications(boolean recompute) {
@@ -1602,7 +1604,7 @@
private boolean isQsExpansionEnabled() {
return mQsExpansionEnabledPolicy && mQsExpansionEnabledAmbient
- && !mRemoteInputManager.getController().isRemoteInputActive();
+ && !mRemoteInputManager.isRemoteInputActive();
}
public void expandWithQs() {
@@ -2280,7 +2282,7 @@
}
}
- protected void updateQsExpansion() {
+ private void updateQsExpansion() {
if (mQs == null) return;
float qsExpansionFraction = computeQsExpansionFraction();
mQs.setQsExpansion(qsExpansionFraction, getHeaderTranslation());
@@ -2340,9 +2342,20 @@
top = mTransitionToFullShadeQSPosition;
} else {
final float notificationTop = getQSEdgePosition();
- top = (int) (isOnKeyguard() ? Math.min(qsPanelBottomY, notificationTop)
- : notificationTop);
+ if (isOnKeyguard()) {
+ if (mKeyguardBypassController.getBypassEnabled()) {
+ // When bypassing on the keyguard, let's use the panel bottom.
+ // this should go away once we unify the stackY position and don't have
+ // to do this min anymore below.
+ top = qsPanelBottomY;
+ } else {
+ top = (int) Math.min(qsPanelBottomY, notificationTop);
+ }
+ } else {
+ top = (int) notificationTop;
+ }
}
+ top += mOverStretchAmount;
bottom = getView().getBottom();
// notification bounds should take full screen width regardless of insets
left = 0;
@@ -2395,6 +2408,7 @@
public void onAnimationEnd(Animator animation) {
mQsClippingAnimation = null;
mIsQsTranslationResetAnimator = false;
+ mIsPulseExpansionResetAnimator = false;
}
});
mQsClippingAnimation.start();
@@ -2420,9 +2434,17 @@
}
if (mQs != null) {
float qsTranslation = 0;
- if (mTransitioningToFullShadeProgress > 0.0f || (mQsClippingAnimation != null
- && mIsQsTranslationResetAnimator)) {
- qsTranslation = (top - mQs.getHeader().getHeight()) * QS_PARALLAX_AMOUNT;
+ boolean pulseExpanding = mPulseExpansionHandler.isExpanding();
+ if (mTransitioningToFullShadeProgress > 0.0f || pulseExpanding
+ || (mQsClippingAnimation != null
+ && (mIsQsTranslationResetAnimator || mIsPulseExpansionResetAnimator))) {
+ if (pulseExpanding || mIsPulseExpansionResetAnimator) {
+ // qsTranslation should only be positive during pulse expansion because it's
+ // already translating in from the top
+ qsTranslation = Math.max(0, (top - mQs.getHeader().getHeight()) / 2.0f);
+ } else {
+ qsTranslation = (top - mQs.getHeader().getHeight()) * QS_PARALLAX_AMOUNT;
+ }
}
mQsTranslationForFullShadeTransition = qsTranslation;
updateQsFrameTranslation();
@@ -2551,14 +2573,6 @@
}
}
- private void updateQSPulseExpansion() {
- if (mQs != null) {
- mQs.setPulseExpanding(
- mKeyguardShowing && mKeyguardBypassController.getBypassEnabled()
- && mNotificationStackScrollLayoutController.isPulseExpanding());
- }
- }
-
/**
* Set the amount of pixels we have currently dragged down if we're transitioning to the full
* shade. 0.0f means we're not transitioning yet.
@@ -2610,6 +2624,15 @@
}
/**
+ * Notify the panel that the pulse expansion has finished and that we're going to the full
+ * shade
+ */
+ public void onPulseExpansionFinished() {
+ animateNextNotificationBounds(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE, 0);
+ mIsPulseExpansionResetAnimator = true;
+ }
+
+ /**
* Set the alpha of the keyguard elements which only show on the lockscreen, but not in
* shade locked / shade. This is used when dragging down to the full shade.
*/
@@ -2966,19 +2989,7 @@
startHeight = -mQsExpansionHeight * QS_PARALLAX_AMOUNT;
}
if (mKeyguardBypassController.getBypassEnabled() && isOnKeyguard()) {
- if (mNotificationStackScrollLayoutController.isPulseExpanding()) {
- if (!mPulseExpansionHandler.isExpanding()
- && !mPulseExpansionHandler.getLeavingLockscreen()) {
- // If we aborted the expansion we need to make sure the header doesn't reappear
- // again after the header has animated away
- appearAmount = 0;
- } else {
- appearAmount = mNotificationStackScrollLayoutController
- .calculateAppearFractionBypass();
- }
- } else {
- appearAmount = 0.0f;
- }
+ appearAmount = mNotificationStackScrollLayoutController.calculateAppearFractionBypass();
startHeight = -mQs.getQsMinExpansionHeight();
}
float translation = MathUtils.lerp(startHeight, 0, Math.min(1.0f, appearAmount));
@@ -3126,7 +3137,7 @@
}
private void setListening(boolean listening) {
- mKeyguardStatusBar.setListening(listening);
+ mKeyguardStatusBarViewController.setBatteryListening(listening);
if (mQs == null) return;
mQs.setListening(listening);
}
@@ -3581,7 +3592,6 @@
mQs.setPanelView(mHeightListener);
mQs.setExpandClickListener(mOnClickListener);
mQs.setHeaderClickable(isQsExpansionEnabled());
- updateQSPulseExpansion();
mQs.setOverscrolling(mStackScrollerOverscrolling);
mQs.setTranslateWhileExpanding(mShouldUseSplitNotificationShade);
@@ -3678,8 +3688,6 @@
public void setAmbientIndicationBottomPadding(int ambientIndicationBottomPadding) {
if (mAmbientIndicationBottomPadding != ambientIndicationBottomPadding) {
mAmbientIndicationBottomPadding = ambientIndicationBottomPadding;
- mLockIconViewController.setAmbientIndicationBottomPadding(
- mAmbientIndicationBottomPadding);
updateMaxDisplayedNotifications(true);
}
}
@@ -3773,8 +3781,8 @@
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
super.dump(fd, pw, args);
pw.println(" gestureExclusionRect: " + calculateGestureExclusionRect());
- if (mKeyguardStatusBar != null) {
- mKeyguardStatusBar.dump(fd, pw, args);
+ if (mKeyguardStatusBarViewController != null) {
+ mKeyguardStatusBarViewController.dump(fd, pw, args);
}
}
@@ -4462,7 +4470,6 @@
updateMaxDisplayedNotifications(false);
// The update needs to happen after the headerSlide in above, otherwise the translation
// would reset
- updateQSPulseExpansion();
maybeAnimateBottomAreaAlpha();
resetHorizontalPanelPosition();
updateQsState();
@@ -4499,7 +4506,9 @@
* Sets the overstretch amount in raw pixels when dragging down.
*/
public void setOverStrechAmount(float amount) {
- mOverStretchAmount = amount;
+ float progress = amount / mView.getHeight();
+ float overstretch = Interpolators.getOvershootInterpolation(progress);
+ mOverStretchAmount = overstretch * mMaxOverscrollAmountForPulse;
positionClockAndNotifications(true /* forceUpdate */);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 31a432e..c300b11 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -23,6 +23,7 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.EventLog;
@@ -52,6 +53,7 @@
private static final boolean DEBUG = StatusBar.DEBUG;
private static final boolean DEBUG_GESTURES = false;
private final CommandQueue mCommandQueue;
+ private final StatusBarContentInsetsProvider mContentInsetsProvider;
StatusBar mBar;
@@ -85,11 +87,10 @@
private int mCutoutSideNudge = 0;
private boolean mHeadsUpVisible;
- private int mRoundedCornerPadding = 0;
-
public PhoneStatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
mCommandQueue = Dependency.get(CommandQueue.class);
+ mContentInsetsProvider = Dependency.get(StatusBarContentInsetsProvider.class);
}
public void setBar(StatusBar bar) {
@@ -305,8 +306,6 @@
public void updateResources() {
mCutoutSideNudge = getResources().getDimensionPixelSize(
R.dimen.display_cutout_margin_consumption);
- mRoundedCornerPadding = getResources().getDimensionPixelSize(
- R.dimen.rounded_corner_content_padding);
updateStatusBarHeight();
}
@@ -341,8 +340,7 @@
private void updateLayoutForCutout() {
updateStatusBarHeight();
updateCutoutLocation(StatusBarWindowView.cornerCutoutMargins(mDisplayCutout, getDisplay()));
- updateSafeInsets(StatusBarWindowView.statusBarCornerCutoutMargins(mDisplayCutout,
- getDisplay(), mRotationOrientation, mStatusBarHeight));
+ updateSafeInsets();
}
private void updateCutoutLocation(Pair<Integer, Integer> cornerCutoutMargins) {
@@ -370,15 +368,18 @@
lp.height = bounds.height();
}
- private void updateSafeInsets(Pair<Integer, Integer> cornerCutoutMargins) {
- // Depending on our rotation, we may have to work around a cutout in the middle of the view,
- // or letterboxing from the right or left sides.
+ private void updateSafeInsets() {
+ Rect contentRect = mContentInsetsProvider
+ .getStatusBarContentInsetsForRotation(RotationUtils.getExactRotation(getContext()));
- Pair<Integer, Integer> padding =
- StatusBarWindowView.paddingNeededForCutoutAndRoundedCorner(
- mDisplayCutout, cornerCutoutMargins, mRoundedCornerPadding);
+ Point size = new Point();
+ getDisplay().getRealSize(size);
- setPadding(padding.first, getPaddingTop(), padding.second, getPaddingBottom());
+ setPadding(
+ contentRect.left,
+ getPaddingTop(),
+ size.x - contentRect.right,
+ getPaddingBottom());
}
public void setHeadsUpVisible(boolean headsUpVisible) {
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 bc3a770..3b5d69d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -39,9 +39,7 @@
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
-import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
-import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING;
import static com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
import static com.android.wm.shell.bubbles.BubbleController.TASKBAR_CHANGED_BROADCAST;
@@ -105,8 +103,8 @@
import android.view.Display;
import android.view.IRemoteAnimationRunner;
import android.view.IWindowManager;
-import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
+import android.view.InsetsVisibilities;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.RemoteAnimationAdapter;
@@ -158,8 +156,6 @@
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.UiBackground;
-import com.android.systemui.demomode.DemoMode;
-import com.android.systemui.demomode.DemoModeCommandReceiver;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.emergency.EmergencyGesture;
import com.android.systemui.fragments.ExtensionFragmentListener;
@@ -245,8 +241,10 @@
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
import com.android.systemui.volume.VolumeComponent;
import com.android.systemui.wmshell.BubblesManager;
+import com.android.unfold.config.UnfoldTransitionConfig;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.startingsurface.SplashscreenContentDrawer;
@@ -266,7 +264,8 @@
import dagger.Lazy;
-public class StatusBar extends SystemUI implements DemoMode,
+/** */
+public class StatusBar extends SystemUI implements
ActivityStarter, KeyguardStateController.Callback,
OnHeadsUpChangedListener, CommandQueue.Callbacks,
ColorExtractor.OnColorsChangedListener, ConfigurationListener,
@@ -442,6 +441,7 @@
private final OngoingCallController mOngoingCallController;
private final SystemStatusAnimationScheduler mAnimationScheduler;
private final StatusBarLocationPublisher mStatusBarLocationPublisher;
+ private final StatusBarIconController mStatusBarIconController;
// expanded notifications
// the sliding/resizing panel within the notification window
@@ -467,6 +467,8 @@
protected final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private final BrightnessSlider.Factory mBrightnessSliderFactory;
private final FeatureFlags mFeatureFlags;
+ private final UnfoldTransitionConfig mUnfoldTransitionConfig;
+ private final Lazy<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealOverlayAnimation;
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
@@ -801,9 +803,12 @@
NotificationIconAreaController notificationIconAreaController,
BrightnessSlider.Factory brightnessSliderFactory,
WiredChargingRippleController chargingRippleAnimationController,
+ UnfoldTransitionConfig unfoldTransitionConfig,
+ Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation,
OngoingCallController ongoingCallController,
SystemStatusAnimationScheduler animationScheduler,
StatusBarLocationPublisher locationPublisher,
+ StatusBarIconController statusBarIconController,
LockscreenShadeTransitionController lockscreenShadeTransitionController,
FeatureFlags featureFlags,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
@@ -887,9 +892,12 @@
mNotificationIconAreaController = notificationIconAreaController;
mBrightnessSliderFactory = brightnessSliderFactory;
mChargingRippleAnimationController = chargingRippleAnimationController;
+ mUnfoldTransitionConfig = unfoldTransitionConfig;
+ mUnfoldLightRevealOverlayAnimation = unfoldLightRevealOverlayAnimation;
mOngoingCallController = ongoingCallController;
mAnimationScheduler = animationScheduler;
mStatusBarLocationPublisher = locationPublisher;
+ mStatusBarIconController = statusBarIconController;
mFeatureFlags = featureFlags;
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
@@ -960,8 +968,6 @@
// Connect in to the status bar manager service
mCommandQueue.addCallback(this);
- // Listen for demo mode changes
- mDemoModeController.addCallback(this);
RegisterStatusBarResult result = null;
try {
@@ -989,7 +995,7 @@
showTransientUnchecked();
}
onSystemBarAttributesChanged(mDisplayId, result.mAppearance, result.mAppearanceRegions,
- result.mNavbarColorManagedByIme, result.mBehavior, result.mRequestedState,
+ result.mNavbarColorManagedByIme, result.mBehavior, result.mRequestedVisibilities,
result.mPackageName);
// StatusBarManagerService has a back up of IME token and it's restored here.
@@ -1058,6 +1064,10 @@
mFalsingManager.addFalsingBeliefListener(mFalsingBeliefListener);
+ if (mUnfoldTransitionConfig.isEnabled()) {
+ mUnfoldLightRevealOverlayAnimation.get().init();
+ }
+
mPluginManager.addPluginListener(
new PluginListener<OverlayPlugin>() {
private ArraySet<OverlayPlugin> mOverlays = new ArraySet<>();
@@ -1193,7 +1203,13 @@
mStatusBarLocationPublisher,
mNotificationIconAreaController,
mFeatureFlags,
- () -> Optional.of(this)),
+ () -> Optional.of(this),
+ mStatusBarIconController,
+ mKeyguardStateController,
+ mNetworkController,
+ mStatusBarStateController,
+ mCommandQueue
+ ),
CollapsedStatusBarFragment.TAG)
.commit();
@@ -1224,7 +1240,7 @@
@Override
public boolean shouldHideOnTouch() {
- return !mRemoteInputManager.getController().isRemoteInputActive();
+ return !mRemoteInputManager.isRemoteInputActive();
}
@Override
@@ -1444,7 +1460,7 @@
mNotificationInterruptStateProvider);
mNotificationShelfController.setOnActivatedListener(mPresenter);
- mRemoteInputManager.getController().addCallback(mNotificationShadeWindowController);
+ mRemoteInputManager.addControllerCallback(mNotificationShadeWindowController);
mNotificationActivityStarter =
mStatusBarNotificationActivityStarterBuilder
@@ -1579,6 +1595,9 @@
mAuthRippleController = statusBarComponent.getAuthRippleController();
mAuthRippleController.init();
+
+ // Listen for demo mode changes
+ mDemoModeController.addCallback(statusBarComponent.getStatusBarDemoMode());
}
protected void startKeyguard() {
@@ -1619,7 +1638,7 @@
mKeyguardIndicationController
.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
- mRemoteInputManager.getController().addCallback(mStatusBarKeyguardViewManager);
+ mRemoteInputManager.addControllerCallback(mStatusBarKeyguardViewManager);
mDynamicPrivacyController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mLightBarController.setBiometricUnlockController(mBiometricUnlockController);
@@ -2494,7 +2513,7 @@
@Override
public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, InsetsState requestedState, String packageName) {
+ @Behavior int behavior, InsetsVisibilities requestedVisibilities, String packageName) {
if (displayId != mDisplayId) {
return;
}
@@ -2508,7 +2527,7 @@
updateBubblesVisibility();
mStatusBarStateController.setSystemBarAttributes(
- appearance, behavior, requestedState, packageName);
+ appearance, behavior, requestedVisibilities, packageName);
}
@Override
@@ -2741,6 +2760,11 @@
mScrimController.dump(fd, pw, args);
}
+ if (mLightRevealScrim != null) {
+ pw.println(
+ "mLightRevealScrim.getRevealAmount(): " + mLightRevealScrim.getRevealAmount());
+ }
+
if (mStatusBarKeyguardViewManager != null) {
mStatusBarKeyguardViewManager.dump(pw);
}
@@ -3037,9 +3061,7 @@
String action = intent.getAction();
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
KeyboardShortcuts.dismiss();
- if (mRemoteInputManager.getController() != null) {
- mRemoteInputManager.getController().closeRemoteInputs();
- }
+ mRemoteInputManager.closeRemoteInputs();
if (mBubblesOptional.isPresent() && mBubblesOptional.get().isStackExpanded()) {
mBubblesOptional.get().collapseStack();
}
@@ -3351,82 +3373,6 @@
delay);
}
- @Override
- public List<String> demoCommands() {
- List<String> s = new ArrayList<>();
- s.add(DemoMode.COMMAND_BARS);
- s.add(DemoMode.COMMAND_CLOCK);
- s.add(DemoMode.COMMAND_OPERATOR);
- return s;
- }
-
- @Override
- public void onDemoModeStarted() {
- // Must send this message to any view that we delegate to via dispatchDemoCommandToView
- dispatchDemoModeStartedToView(R.id.clock);
- dispatchDemoModeStartedToView(R.id.operator_name);
- }
-
- @Override
- public void onDemoModeFinished() {
- dispatchDemoModeFinishedToView(R.id.clock);
- dispatchDemoModeFinishedToView(R.id.operator_name);
- checkBarModes();
- }
-
- @Override
- public void dispatchDemoCommand(String command, @NonNull Bundle args) {
- if (command.equals(COMMAND_CLOCK)) {
- dispatchDemoCommandToView(command, args, R.id.clock);
- }
- if (command.equals(COMMAND_BARS)) {
- String mode = args.getString("mode");
- int barMode = "opaque".equals(mode) ? MODE_OPAQUE :
- "translucent".equals(mode) ? MODE_TRANSLUCENT :
- "semi-transparent".equals(mode) ? MODE_SEMI_TRANSPARENT :
- "transparent".equals(mode) ? MODE_TRANSPARENT :
- "warning".equals(mode) ? MODE_WARNING :
- -1;
- if (barMode != -1) {
- boolean animate = true;
- if (mNotificationShadeWindowController != null
- && mNotificationShadeWindowViewController.getBarTransitions() != null) {
- mNotificationShadeWindowViewController.getBarTransitions().transitionTo(
- barMode, animate);
- }
- mNavigationBarController.transitionTo(mDisplayId, barMode, animate);
- }
- }
- if (command.equals(COMMAND_OPERATOR)) {
- dispatchDemoCommandToView(command, args, R.id.operator_name);
- }
- }
-
- //TODO: these should have controllers, and this method should be removed
- private void dispatchDemoCommandToView(String command, Bundle args, int id) {
- if (mStatusBarView == null) return;
- View v = mStatusBarView.findViewById(id);
- if (v instanceof DemoModeCommandReceiver) {
- ((DemoModeCommandReceiver) v).dispatchDemoCommand(command, args);
- }
- }
-
- private void dispatchDemoModeStartedToView(int id) {
- if (mStatusBarView == null) return;
- View v = mStatusBarView.findViewById(id);
- if (v instanceof DemoModeCommandReceiver) {
- ((DemoModeCommandReceiver) v).onDemoModeStarted();
- }
- }
-
- private void dispatchDemoModeFinishedToView(int id) {
- if (mStatusBarView == null) return;
- View v = mStatusBarView.findViewById(id);
- if (v instanceof DemoModeCommandReceiver) {
- ((DemoModeCommandReceiver) v).onDemoModeFinished();
- }
- }
-
public void showKeyguard() {
mStatusBarStateController.setKeyguardRequested(true);
mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
@@ -3605,6 +3551,7 @@
mIsKeyguard = false;
Trace.beginSection("StatusBar#hideKeyguard");
boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide();
+ int previousState = mStatusBarStateController.getState();
if (!(mStatusBarStateController.setState(StatusBarState.SHADE, force))) {
//TODO: StatusBarStateController should probably know about hiding the keyguard and
// notify listeners.
@@ -3617,7 +3564,7 @@
mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
}
long delay = mKeyguardStateController.calculateGoingToFullShadeDelay();
- mLockscreenShadeTransitionController.onHideKeyguard(delay);
+ mLockscreenShadeTransitionController.onHideKeyguard(delay, previousState);
// Disable layout transitions in navbar for this transition because the load is just
// too heavy for the CPU and GPU on any device.
@@ -3939,7 +3886,11 @@
|| !wakingUp && mWakefulnessLifecycle.getLastSleepReason()
== PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON) {
mLightRevealScrim.setRevealEffect(mPowerButtonReveal);
- } else if (!(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)) {
+ } else if (!wakingUp || !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)) {
+ // If we're going to sleep, but it's not from the power button, use the default reveal.
+ // If we're waking up, only use the default reveal if the biometric controller didn't
+ // already set it to the circular reveal because we're waking up from a fingerprint/face
+ // auth.
mLightRevealScrim.setRevealEffect(LiftReveal.INSTANCE);
}
}
@@ -3968,7 +3919,7 @@
public void onUnlockHintStarted() {
mFalsingCollector.onUnlockHintStarted();
- mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock);
+ mKeyguardIndicationController.showActionToUnlock();
}
public void onHintFinished() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt
index edcf261..fe1f63a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt
@@ -19,6 +19,7 @@
import android.content.Context
import android.content.res.Resources
import android.graphics.Rect
+import android.util.Log
import android.util.Pair
import android.view.DisplayCutout
import android.view.View.LAYOUT_DIRECTION_RTL
@@ -155,13 +156,30 @@
val dc = context.display.cutout
val currentRotation = RotationUtils.getExactRotation(context)
+ val isRtl = rotatedResources.configuration.layoutDirection == LAYOUT_DIRECTION_RTL
+ val roundedCornerPadding = rotatedResources
+ .getDimensionPixelSize(R.dimen.rounded_corner_content_padding)
+ val minDotWidth = rotatedResources
+ .getDimensionPixelSize(R.dimen.ongoing_appops_dot_min_padding)
+
+ val minLeft: Int
+ val minRight: Int
+ if (isRtl) {
+ minLeft = max(minDotWidth, roundedCornerPadding)
+ minRight = roundedCornerPadding
+ } else {
+ minLeft = roundedCornerPadding
+ minRight = max(minDotWidth, roundedCornerPadding)
+ }
+
return calculateInsetsForRotationWithRotatedResources(
currentRotation,
targetRotation,
dc,
windowManager.maximumWindowMetrics,
rotatedResources.getDimensionPixelSize(R.dimen.status_bar_height),
- rotatedResources.getDimensionPixelSize(R.dimen.rounded_corner_content_padding))
+ minLeft,
+ minRight)
}
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
@@ -212,9 +230,12 @@
* Calculates the exact left and right positions for the status bar contents for the given
* rotation
*
- * @param rot rotation for which to query the margins
- * @param context systemui context
- * @param rotatedResources resources constructed with the proper orientation set
+ * @param currentRotation current device rotation
+ * @param targetRotation rotation for which to calculate the status bar content rect
+ * @param displayCutout [DisplayCutout] for the curren display. possibly null
+ * @param windowMetrics [WindowMetrics] for the current window
+ * @param statusBarHeight height of the status bar for the target rotation
+ * @param roundedCornerPadding from rounded_corner_content_padding
*
* @see [RotationUtils#getResourcesForRotation]
*/
@@ -224,7 +245,8 @@
displayCutout: DisplayCutout?,
windowMetrics: WindowMetrics,
statusBarHeight: Int,
- roundedCornerPadding: Int
+ minLeft: Int,
+ minRight: Int
): Rect {
/*
TODO: Check if this is ever used for devices with no rounded corners
@@ -242,7 +264,8 @@
rotZeroBounds.bottom,
currentBounds.width(),
currentBounds.height(),
- roundedCornerPadding,
+ minLeft,
+ minRight,
targetRotation,
currentRotation)
@@ -256,7 +279,10 @@
* @param sbHeight appropriate status bar height for this rotation
* @param width display width calculated for ROTATION_NONE
* @param height display height calculated for ROTATION_NONE
- * @param roundedCornerPadding rounded_corner_content_padding dimension
+ * @param cWidth display width in our current rotation
+ * @param cHeight display height in our current rotation
+ * @param minLeft the minimum padding to enforce on the left
+ * @param minRight the minimum padding to enforce on the right
* @param targetRotation the rotation for which to calculate margins
* @param currentRotation the rotation from which the display cutout was generated
*
@@ -270,7 +296,8 @@
height: Int,
cWidth: Int,
cHeight: Int,
- roundedCornerPadding: Int,
+ minLeft: Int,
+ minRight: Int,
@Rotation targetRotation: Int,
@Rotation currentRotation: Int
): Rect {
@@ -279,9 +306,9 @@
val cutoutRects = dc?.boundingRects
if (cutoutRects == null || cutoutRects.isEmpty()) {
- return Rect(roundedCornerPadding,
+ return Rect(minLeft,
0,
- logicalDisplayWidth - roundedCornerPadding,
+ logicalDisplayWidth - minRight,
sbHeight)
}
@@ -294,8 +321,8 @@
// Size of the status bar window for the given rotation relative to our exact rotation
val sbRect = sbRect(relativeRotation, sbHeight, Pair(cWidth, cHeight))
- var leftMargin = roundedCornerPadding
- var rightMargin = roundedCornerPadding
+ var leftMargin = minLeft
+ var rightMargin = minRight
for (cutoutRect in cutoutRects) {
// There is at most one non-functional area per short edge of the device. So if the status
// bar doesn't share a short edge with the cutout, we can ignore its insets because there
@@ -306,11 +333,11 @@
if (cutoutRect.touchesLeftEdge(relativeRotation, cWidth, cHeight)) {
- val l = max(roundedCornerPadding, cutoutRect.logicalWidth(relativeRotation))
+ val l = max(minLeft, cutoutRect.logicalWidth(relativeRotation))
leftMargin = max(l, leftMargin)
} else if (cutoutRect.touchesRightEdge(relativeRotation, cWidth, cHeight)) {
val logicalWidth = cutoutRect.logicalWidth(relativeRotation)
- rightMargin = max(roundedCornerPadding, logicalWidth)
+ rightMargin = max(minRight, logicalWidth)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarDemoMode.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarDemoMode.java
new file mode 100644
index 0000000..8938f96
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarDemoMode.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING;
+
+import android.annotation.NonNull;
+import android.os.Bundle;
+import android.view.View;
+
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.DisplayId;
+import com.android.systemui.demomode.DemoMode;
+import com.android.systemui.demomode.DemoModeCommandReceiver;
+import com.android.systemui.navigationbar.NavigationBarController;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+/** */
+@StatusBarComponent.StatusBarScope
+public class StatusBarDemoMode implements DemoMode {
+ private final StatusBar mStatusBar;
+ private final NotificationShadeWindowController mNotificationShadeWindowController;
+ private final NotificationShadeWindowViewController mNotificationShadeWindowViewController;
+ private final NavigationBarController mNavigationBarController;
+ private final int mDisplayId;
+
+ @Inject
+ StatusBarDemoMode(
+ StatusBar statusBar,
+ NotificationShadeWindowController notificationShadeWindowController,
+ NotificationShadeWindowViewController notificationShadeWindowViewController,
+ NavigationBarController navigationBarController,
+ @DisplayId int displayId) {
+ mStatusBar = statusBar;
+ mNotificationShadeWindowController = notificationShadeWindowController;
+ mNotificationShadeWindowViewController = notificationShadeWindowViewController;
+ mNavigationBarController = navigationBarController;
+ mDisplayId = displayId;
+ }
+
+ @Override
+ public List<String> demoCommands() {
+ List<String> s = new ArrayList<>();
+ s.add(DemoMode.COMMAND_BARS);
+ s.add(DemoMode.COMMAND_CLOCK);
+ s.add(DemoMode.COMMAND_OPERATOR);
+ return s;
+ }
+
+ @Override
+ public void onDemoModeStarted() {
+ // Must send this message to any view that we delegate to via dispatchDemoCommandToView
+ dispatchDemoModeStartedToView(R.id.clock);
+ dispatchDemoModeStartedToView(R.id.operator_name);
+ }
+
+ @Override
+ public void onDemoModeFinished() {
+ dispatchDemoModeFinishedToView(R.id.clock);
+ dispatchDemoModeFinishedToView(R.id.operator_name);
+ mStatusBar.checkBarModes();
+ }
+
+ @Override
+ public void dispatchDemoCommand(String command, @NonNull Bundle args) {
+ if (command.equals(COMMAND_CLOCK)) {
+ dispatchDemoCommandToView(command, args, R.id.clock);
+ }
+ if (command.equals(COMMAND_BARS)) {
+ String mode = args.getString("mode");
+ int barMode = "opaque".equals(mode) ? MODE_OPAQUE :
+ "translucent".equals(mode) ? MODE_TRANSLUCENT :
+ "semi-transparent".equals(mode) ? MODE_SEMI_TRANSPARENT :
+ "transparent".equals(mode) ? MODE_TRANSPARENT :
+ "warning".equals(mode) ? MODE_WARNING :
+ -1;
+ if (barMode != -1) {
+ boolean animate = true;
+ if (mNotificationShadeWindowController != null
+ && mNotificationShadeWindowViewController.getBarTransitions() != null) {
+ mNotificationShadeWindowViewController.getBarTransitions().transitionTo(
+ barMode, animate);
+ }
+ mNavigationBarController.transitionTo(mDisplayId, barMode, animate);
+ }
+ }
+ if (command.equals(COMMAND_OPERATOR)) {
+ dispatchDemoCommandToView(command, args, R.id.operator_name);
+ }
+ }
+
+
+ private void dispatchDemoModeStartedToView(int id) {
+ View statusBarView = mStatusBar.getStatusBarView();
+ if (statusBarView == null) return;
+ View v = statusBarView.findViewById(id);
+ if (v instanceof DemoModeCommandReceiver) {
+ ((DemoModeCommandReceiver) v).onDemoModeStarted();
+ }
+ }
+
+ //TODO: these should have controllers, and this method should be removed
+ private void dispatchDemoCommandToView(String command, Bundle args, int id) {
+ View statusBarView = mStatusBar.getStatusBarView();
+ if (statusBarView == null) return;
+ View v = statusBarView.findViewById(id);
+ if (v instanceof DemoModeCommandReceiver) {
+ ((DemoModeCommandReceiver) v).dispatchDemoCommand(command, args);
+ }
+ }
+
+ private void dispatchDemoModeFinishedToView(int id) {
+ View statusBarView = mStatusBar.getStatusBarView();
+ if (statusBarView == null) return;
+ View v = statusBarView.findViewById(id);
+ if (v instanceof DemoModeCommandReceiver) {
+ ((DemoModeCommandReceiver) v).onDemoModeFinished();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 2c75534..dbe4c1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -35,6 +35,7 @@
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.demomode.DemoModeCommandReceiver;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
@@ -50,6 +51,8 @@
import java.util.ArrayList;
import java.util.List;
+import javax.inject.Inject;
+
public interface StatusBarIconController {
/**
@@ -213,6 +216,20 @@
icons.setColor(mColor);
return icons;
}
+
+ @SysUISingleton
+ public static class Factory {
+ private final FeatureFlags mFeatureFlags;
+
+ @Inject
+ public Factory(FeatureFlags featureFlags) {
+ mFeatureFlags = featureFlags;
+ }
+
+ public TintedIconManager create(ViewGroup group) {
+ return new TintedIconManager(group, mFeatureFlags);
+ }
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index 75900a2..9d1c1e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -23,6 +23,7 @@
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
import android.view.ViewGroup;
import com.android.internal.statusbar.StatusBarIcon;
@@ -88,6 +89,13 @@
/** */
@Override
public void addIconGroup(IconManager group) {
+ for (IconManager existingIconManager : mIconGroups) {
+ if (existingIconManager.mGroup == group.mGroup) {
+ Log.e(TAG, "Adding new IconManager for the same ViewGroup. This could cause "
+ + "unexpected results.");
+ }
+ }
+
mIconGroups.add(group);
List<Slot> allSlots = getSlots();
for (int i = 0; i < allSlots.size(); i++) {
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 9a6dd38..1717b82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -60,7 +60,6 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -230,12 +229,11 @@
mLogger.logStartingActivityFromClick(sbn.getKey());
final NotificationEntry entry = row.getEntry();
- RemoteInputController controller = mRemoteInputManager.getController();
- if (controller.isRemoteInputActive(entry)
+ if (mRemoteInputManager.isRemoteInputActive(entry)
&& !TextUtils.isEmpty(row.getActiveRemoteInputText())) {
// We have an active remote input typed and the user clicked on the notification.
// this was probably unintentional, so we're closing the edit text instead.
- controller.closeRemoteInputs();
+ mRemoteInputManager.closeRemoteInputs();
return;
}
Notification notification = sbn.getNotification();
@@ -265,8 +263,7 @@
@Override
public boolean onDismiss() {
return handleNotificationClickAfterKeyguardDismissed(
- entry, row, controller, intent,
- isActivityIntent, animate, showOverLockscreen);
+ entry, row, intent, isActivityIntent, animate, showOverLockscreen);
}
@Override
@@ -286,7 +283,6 @@
private boolean handleNotificationClickAfterKeyguardDismissed(
NotificationEntry entry,
ExpandableNotificationRow row,
- RemoteInputController controller,
PendingIntent intent,
boolean isActivityIntent,
boolean animate,
@@ -294,8 +290,7 @@
mLogger.logHandleClickAfterKeyguardDismissed(entry.getKey());
final Runnable runnable = () -> handleNotificationClickAfterPanelCollapsed(
- entry, row, controller, intent,
- isActivityIntent, animate);
+ entry, row, intent, isActivityIntent, animate);
if (showOverLockscreen) {
mShadeController.addPostCollapseAction(runnable);
@@ -315,7 +310,6 @@
private void handleNotificationClickAfterPanelCollapsed(
NotificationEntry entry,
ExpandableNotificationRow row,
- RemoteInputController controller,
PendingIntent intent,
boolean isActivityIntent,
boolean animate) {
@@ -354,7 +348,8 @@
if (!TextUtils.isEmpty(entry.remoteInputText)) {
remoteInputText = entry.remoteInputText;
}
- if (!TextUtils.isEmpty(remoteInputText) && !controller.isSpinning(notificationKey)) {
+ if (!TextUtils.isEmpty(remoteInputText)
+ && !mRemoteInputManager.isSpinning(notificationKey)) {
fillInIntent = new Intent().putExtra(Notification.EXTRA_REMOTE_INPUT_DRAFT,
remoteInputText.toString());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index aa58527..cb844d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -24,12 +24,14 @@
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemClock;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
import android.util.Log;
import android.util.Slog;
+import android.view.View;
import android.view.accessibility.AccessibilityManager;
import android.widget.TextView;
@@ -179,8 +181,6 @@
remoteInputManager.setUpWithCallback(
Dependency.get(NotificationRemoteInputManager.Callback.class),
mNotificationPanel.createRemoteInputDelegate());
- remoteInputManager.getController().addCallback(
- Dependency.get(NotificationShadeWindowController.class));
initController.addPostInitTask(() -> {
NotificationEntryListener notificationEntryListener = new NotificationEntryListener() {
@@ -394,8 +394,10 @@
}
@Override
- public void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded) {
+ public void onExpandClicked(NotificationEntry clickedEntry, View clickedView,
+ boolean nowExpanded) {
mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
+ mStatusBar.wakeUpIfDozing(SystemClock.uptimeMillis(), clickedView, "NOTIFICATION_CLICK");
if (nowExpanded) {
if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
mShadeTransitionController.goToLockedShade(clickedEntry.getRow());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
index 4fab226..a4063bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
@@ -24,6 +24,7 @@
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController;
import com.android.systemui.statusbar.phone.SplitShadeHeaderController;
+import com.android.systemui.statusbar.phone.StatusBarDemoMode;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
import java.lang.annotation.Documented;
@@ -89,6 +90,12 @@
AuthRippleController getAuthRippleController();
/**
+ * Creates a StatusBarDemoMode.
+ */
+ @StatusBarScope
+ StatusBarDemoMode getStatusBarDemoMode();
+
+ /**
* Creates a SplitShadeHeaderController.
*/
@StatusBarScope
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 716d1db..5e8eecb 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
@@ -48,6 +48,7 @@
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.settings.brightness.BrightnessSlider;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.unfold.config.UnfoldTransitionConfig;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -89,6 +90,7 @@
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarLocationPublisher;
import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
@@ -105,6 +107,7 @@
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
import com.android.systemui.volume.VolumeComponent;
import com.android.systemui.wmshell.BubblesManager;
import com.android.wm.shell.bubbles.Bubbles;
@@ -213,9 +216,12 @@
NotificationIconAreaController notificationIconAreaController,
BrightnessSlider.Factory brightnessSliderFactory,
WiredChargingRippleController chargingRippleAnimationController,
+ UnfoldTransitionConfig unfoldTransitionConfig,
+ Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation,
OngoingCallController ongoingCallController,
SystemStatusAnimationScheduler animationScheduler,
StatusBarLocationPublisher locationPublisher,
+ StatusBarIconController statusBarIconController,
LockscreenShadeTransitionController transitionController,
FeatureFlags featureFlags,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
@@ -302,9 +308,12 @@
notificationIconAreaController,
brightnessSliderFactory,
chargingRippleAnimationController,
+ unfoldTransitionConfig,
+ unfoldLightRevealOverlayAnimation,
ongoingCallController,
animationScheduler,
locationPublisher,
+ statusBarIconController,
transitionController,
featureFlags,
keyguardUnlockAnimationController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
index c2bd87c..3a05ec7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
@@ -30,6 +30,9 @@
/** Alert controller of a change in between light and dark themes. */
void notifyThemeChanged();
+ /** Query the current configuration's layout direction */
+ boolean isLayoutRtl();
+
interface ConfigurationListener {
default void onConfigChanged(Configuration newConfig) {}
default void onDensityOrFontScaleChanged() {}
@@ -38,5 +41,6 @@
default void onUiModeChanged() {}
default void onThemeChanged() {}
default void onLocaleListChanged() {}
+ default void onLayoutDirectionChanged(boolean isLayoutRtl) {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureController.java
new file mode 100644
index 0000000..fbfa5e5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureController.java
@@ -0,0 +1,58 @@
+/*
+ * 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.policy;
+
+import static com.android.systemui.statusbar.policy.DevicePostureController.Callback;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Listener for device posture changes. This can be used to query the current posture, or register
+ * for events when it changes.
+ */
+public interface DevicePostureController extends CallbackController<Callback> {
+ @IntDef(prefix = {"DEVICE_POSTURE_"}, value = {
+ DEVICE_POSTURE_UNKNOWN,
+ DEVICE_POSTURE_CLOSED,
+ DEVICE_POSTURE_HALF_OPENED,
+ DEVICE_POSTURE_OPENED,
+ DEVICE_POSTURE_FLIPPED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface DevicePostureInt {}
+
+ // NOTE: These constants **must** match those defined for Jetpack Sidecar. This is because we
+ // use the Device State -> Jetpack Posture map in DevicePostureControllerImpl to translate
+ // between the two.
+ int DEVICE_POSTURE_UNKNOWN = 0;
+ int DEVICE_POSTURE_CLOSED = 1;
+ int DEVICE_POSTURE_HALF_OPENED = 2;
+ int DEVICE_POSTURE_OPENED = 3;
+ int DEVICE_POSTURE_FLIPPED = 4;
+
+ /** Return the current device posture. */
+ @DevicePostureInt int getDevicePosture();
+
+ /** Callback to be notified about device posture changes. */
+ interface Callback {
+ /** Called when the posture changes. */
+ void onPostureChanged(@DevicePostureInt int posture);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
new file mode 100644
index 0000000..8471e0a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
@@ -0,0 +1,94 @@
+/*
+ * 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.policy;
+
+import android.content.Context;
+import android.hardware.devicestate.DeviceStateManager;
+import android.util.SparseIntArray;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.R;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
+/** Implementation of {@link DevicePostureController} using the DeviceStateManager. */
+@SysUISingleton
+public class DevicePostureControllerImpl implements DevicePostureController {
+ private final List<Callback> mListeners = new ArrayList<>();
+ private int mCurrentDevicePosture = DEVICE_POSTURE_UNKNOWN;
+
+ private final SparseIntArray mDeviceStateToPostureMap = new SparseIntArray();
+
+ @Inject
+ public DevicePostureControllerImpl(
+ Context context, DeviceStateManager deviceStateManager, @Main Executor executor) {
+ // Most of this is borrowed from WindowManager/Jetpack/DeviceStateManagerPostureProducer.
+ // Using the sidecar/extension libraries directly brings in a new dependency that it'd be
+ // good to avoid (along with the fact that sidecar is deprecated, and extensions isn't fully
+ // ready yet), and we'd have to make our own layer over the sidecar library anyway to easily
+ // allow the implementation to change, so it was easier to just interface with
+ // DeviceStateManager directly.
+ String[] deviceStatePosturePairs = context.getResources()
+ .getStringArray(R.array.config_device_state_postures);
+ for (String deviceStatePosturePair : deviceStatePosturePairs) {
+ String[] deviceStatePostureMapping = deviceStatePosturePair.split(":");
+ if (deviceStatePostureMapping.length != 2) {
+ continue;
+ }
+
+ int deviceState;
+ int posture;
+ try {
+ deviceState = Integer.parseInt(deviceStatePostureMapping[0]);
+ posture = Integer.parseInt(deviceStatePostureMapping[1]);
+ } catch (NumberFormatException e) {
+ continue;
+ }
+
+ mDeviceStateToPostureMap.put(deviceState, posture);
+ }
+
+ deviceStateManager.registerCallback(executor, state -> {
+ mCurrentDevicePosture =
+ mDeviceStateToPostureMap.get(state, DEVICE_POSTURE_UNKNOWN);
+
+ mListeners.forEach(l -> l.onPostureChanged(mCurrentDevicePosture));
+ });
+ }
+
+ @Override
+ public void addCallback(@NonNull Callback listener) {
+ mListeners.add(listener);
+ }
+
+ @Override
+ public void removeCallback(@NonNull Callback listener) {
+ mListeners.remove(listener);
+ }
+
+ @Override
+ public int getDevicePosture() {
+ return mCurrentDevicePosture;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index c94eaed..ae73f73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -23,6 +23,7 @@
import android.annotation.UserIdInt;
import android.app.ActivityManager;
+import android.app.AlertDialog;
import android.app.Dialog;
import android.app.IActivityTaskManager;
import android.content.BroadcastReceiver;
@@ -71,9 +72,11 @@
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.qs.QSUserSwitcherEvent;
import com.android.systemui.qs.tiles.UserDetailView;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.user.CreateUserActivity;
+import com.android.systemui.util.settings.SecureSettings;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -104,9 +107,12 @@
private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
protected final Context mContext;
+ protected final UserTracker mUserTracker;
protected final UserManager mUserManager;
+ private final ContentObserver mSettingsObserver;
private final ArrayList<WeakReference<BaseUserAdapter>> mAdapters = new ArrayList<>();
- private final GuestResumeSessionReceiver mGuestResumeSessionReceiver;
+ @VisibleForTesting
+ final GuestResumeSessionReceiver mGuestResumeSessionReceiver;
private final KeyguardStateController mKeyguardStateController;
protected final Handler mHandler;
private final ActivityStarter mActivityStarter;
@@ -115,15 +121,18 @@
private final IActivityTaskManager mActivityTaskManager;
private ArrayList<UserRecord> mUsers = new ArrayList<>();
- private Dialog mExitGuestDialog;
- private Dialog mAddUserDialog;
+ @VisibleForTesting
+ AlertDialog mExitGuestDialog;
+ @VisibleForTesting
+ Dialog mAddUserDialog;
private int mLastNonGuestUser = UserHandle.USER_SYSTEM;
private boolean mResumeUserOnGuestLogout = true;
private boolean mSimpleUserSwitcher;
// When false, there won't be any visual affordance to add a new user from the keyguard even if
// the user is unlocked
private boolean mAddUsersFromLockScreen;
- private boolean mPauseRefreshUsers;
+ @VisibleForTesting
+ boolean mPauseRefreshUsers;
private int mSecondaryUser = UserHandle.USER_NULL;
private Intent mSecondaryUserServiceIntent;
private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2);
@@ -131,11 +140,14 @@
public final DetailAdapter mUserDetailAdapter;
private final Executor mUiBgExecutor;
private final boolean mGuestUserAutoCreated;
+ private final AtomicBoolean mGuestIsResetting;
private final AtomicBoolean mGuestCreationScheduled;
private FalsingManager mFalsingManager;
@Inject
public UserSwitcherController(Context context,
+ UserManager userManager,
+ UserTracker userTracker,
KeyguardStateController keyguardStateController,
@Main Handler handler,
ActivityStarter activityStarter,
@@ -145,14 +157,17 @@
TelephonyListenerManager telephonyListenerManager,
IActivityTaskManager activityTaskManager,
UserDetailAdapter userDetailAdapter,
+ SecureSettings secureSettings,
@UiBackground Executor uiBgExecutor) {
mContext = context;
+ mUserTracker = userTracker;
mBroadcastDispatcher = broadcastDispatcher;
mTelephonyListenerManager = telephonyListenerManager;
mActivityTaskManager = activityTaskManager;
mUiEventLogger = uiEventLogger;
mFalsingManager = falsingManager;
- mGuestResumeSessionReceiver = new GuestResumeSessionReceiver(this, mUiEventLogger);
+ mGuestResumeSessionReceiver = new GuestResumeSessionReceiver(
+ this, mUserTracker, mUiEventLogger, secureSettings);
mUserDetailAdapter = userDetailAdapter;
mUiBgExecutor = uiBgExecutor;
if (!UserManager.isGuestUserEphemeral()) {
@@ -160,11 +175,12 @@
}
mGuestUserAutoCreated = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_guestUserAutoCreated);
+ mGuestIsResetting = new AtomicBoolean();
mGuestCreationScheduled = new AtomicBoolean();
mKeyguardStateController = keyguardStateController;
mHandler = handler;
mActivityStarter = activityStarter;
- mUserManager = UserManager.get(context);
+ mUserManager = userManager;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_REMOVED);
@@ -183,6 +199,15 @@
mContext.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM, filter,
PERMISSION_SELF, null /* scheduler */);
+ mSettingsObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ mSimpleUserSwitcher = shouldUseSimpleUserSwitcher();
+ mAddUsersFromLockScreen = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.ADD_USERS_WHEN_LOCKED, 0) != 0;
+ refreshUsers(UserHandle.USER_NULL);
+ };
+ };
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(SIMPLE_USER_SWITCHER_GLOBAL_SETTING), true,
mSettingsObserver);
@@ -244,11 +269,11 @@
return null;
}
ArrayList<UserRecord> records = new ArrayList<>(infos.size());
- int currentId = ActivityManager.getCurrentUser();
+ int currentId = mUserTracker.getUserId();
// Check user switchability of the foreground user since SystemUI is running in
// User 0
boolean canSwitchUsers = mUserManager.getUserSwitchability(
- UserHandle.of(ActivityManager.getCurrentUser())) == SWITCHABILITY_STATUS_OK;
+ UserHandle.of(mUserTracker.getUserId())) == SWITCHABILITY_STATUS_OK;
UserInfo currentUserInfo = null;
UserRecord guestRecord = null;
@@ -301,7 +326,20 @@
boolean createIsRestricted = !addUsersWhenLocked;
if (guestRecord == null) {
- if (canCreateGuest) {
+ if (mGuestUserAutoCreated) {
+ // If mGuestIsResetting=true, the switch should be disabled since
+ // we will just use it as an indicator for "Resetting guest...".
+ // Otherwise, default to canSwitchUsers.
+ boolean isSwitchToGuestEnabled =
+ !mGuestIsResetting.get() && canSwitchUsers;
+ guestRecord = new UserRecord(null /* info */, null /* picture */,
+ true /* isGuest */, false /* isCurrent */,
+ false /* isAddUser */, false /* isRestricted */,
+ isSwitchToGuestEnabled);
+ // Don't call checkIfAddUserDisallowedByAdminOnly if
+ // config_guestUserAutoCreated=true.
+ records.add(guestRecord);
+ } else if (canCreateGuest) {
guestRecord = new UserRecord(null /* info */, null /* picture */,
true /* isGuest */, false /* isCurrent */,
false /* isAddUser */, createIsRestricted, canSwitchUsers);
@@ -376,7 +414,7 @@
}
public void logoutCurrentUser() {
- int currentUser = ActivityManager.getCurrentUser();
+ int currentUser = mUserTracker.getUserId();
if (currentUser != UserHandle.USER_SYSTEM) {
pauseRefreshUsers();
ActivityManager.logoutCurrentUser();
@@ -388,7 +426,7 @@
Log.w(TAG, "User " + userId + " could not removed.");
return;
}
- if (ActivityManager.getCurrentUser() == userId) {
+ if (mUserTracker.getUserId() == userId) {
switchToUserId(UserHandle.USER_SYSTEM);
}
if (mUserManager.removeUser(userId)) {
@@ -396,7 +434,8 @@
}
}
- private void onUserListItemClicked(UserRecord record) {
+ @VisibleForTesting
+ void onUserListItemClicked(UserRecord record) {
int id;
if (record.isGuest && record.info == null) {
// No guest user. Create one.
@@ -414,7 +453,7 @@
id = record.info.id;
}
- int currUserId = ActivityManager.getCurrentUser();
+ int currUserId = mUserTracker.getUserId();
if (currUserId == id) {
if (record.isGuest) {
showExitGuestDialog(id);
@@ -572,15 +611,6 @@
}
};
- private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) {
- public void onChange(boolean selfChange) {
- mSimpleUserSwitcher = shouldUseSimpleUserSwitcher();
- mAddUsersFromLockScreen = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.ADD_USERS_WHEN_LOCKED, 0) != 0;
- refreshUsers(UserHandle.USER_NULL);
- };
- };
-
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("UserSwitcherController state:");
@@ -639,13 +669,7 @@
* UserHandle.USER_NULL}, then switch immediately to the newly created guest user.
*/
public void removeGuestUser(@UserIdInt int guestUserId, @UserIdInt int targetUserId) {
- UserInfo currentUser;
- try {
- currentUser = ActivityManager.getService().getCurrentUser();
- } catch (RemoteException e) {
- Log.e(TAG, "Couldn't remove guest because ActivityManager is dead");
- return;
- }
+ UserInfo currentUser = mUserTracker.getUserInfo();
if (currentUser.id != guestUserId) {
Log.w(TAG, "User requesting to start a new session (" + guestUserId + ")"
+ " is not current user (" + currentUser.id + ")");
@@ -677,6 +701,9 @@
switchToUserId(newGuestId);
mUserManager.removeUser(currentUser.id);
} else {
+ if (mGuestUserAutoCreated) {
+ mGuestIsResetting.set(true);
+ }
switchToUserId(targetUserId);
mUserManager.removeUser(currentUser.id);
}
@@ -693,10 +720,14 @@
mUiBgExecutor.execute(() -> {
int newGuestId = createGuest();
+ mGuestCreationScheduled.set(false);
+ mGuestIsResetting.set(false);
if (newGuestId == UserHandle.USER_NULL) {
Log.w(TAG, "Could not create new guest while exiting existing guest");
+ // Refresh users so that we still display "Guest" if
+ // config_guestUserAutoCreated=true
+ refreshUsers(UserHandle.USER_NULL);
}
- mGuestCreationScheduled.set(false);
});
}
@@ -799,12 +830,25 @@
? com.android.settingslib.R.string.guest_reset_guest
: com.android.settingslib.R.string.guest_exit_guest);
} else {
- // If config_guestUserAutoCreated, always show guest nickname instead of "Add
- // guest" to make it seem as though the device always has a guest ready for use
- return context.getString(
- item.info == null && !mController.mGuestUserAutoCreated
- ? com.android.settingslib.R.string.guest_new_guest
- : com.android.settingslib.R.string.guest_nickname);
+ if (item.info != null) {
+ return context.getString(com.android.settingslib.R.string.guest_nickname);
+ } else {
+ if (mController.mGuestUserAutoCreated) {
+ // If mGuestIsResetting=true, we expect the guest user to be created
+ // shortly, so display a "Resetting guest..." as an indicator that we
+ // are busy. Otherwise, if mGuestIsResetting=false, we probably failed
+ // to create a guest at some point. In this case, always show guest
+ // nickname instead of "Add guest" to make it seem as though the device
+ // always has a guest ready for use.
+ return context.getString(
+ mController.mGuestIsResetting.get()
+ ? com.android.settingslib.R.string.guest_resetting
+ : com.android.settingslib.R.string.guest_nickname);
+ } else {
+ return context.getString(
+ com.android.settingslib.R.string.guest_new_guest);
+ }
+ }
}
} else if (item.isAddUser) {
return context.getString(R.string.user_add_user);
@@ -839,9 +883,9 @@
private void checkIfAddUserDisallowedByAdminOnly(UserRecord record) {
EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced(mContext,
- UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser());
+ UserManager.DISALLOW_ADD_USER, mUserTracker.getUserId());
if (admin != null && !RestrictedLockUtilsInternal.hasBaseUserRestriction(mContext,
- UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser())) {
+ UserManager.DISALLOW_ADD_USER, mUserTracker.getUserId())) {
record.isDisabledByAdmin = true;
record.enforcedAdmin = admin;
} else {
@@ -1053,7 +1097,8 @@
}
}
- private final class AddUserDialog extends SystemUIDialog implements
+ @VisibleForTesting
+ final class AddUserDialog extends SystemUIDialog implements
DialogInterface.OnClickListener {
public AddUserDialog(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
index 9fb0453..c224cf5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
@@ -28,6 +28,8 @@
import com.android.systemui.statusbar.policy.CastControllerImpl;
import com.android.systemui.statusbar.policy.DeviceControlsController;
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl;
+import com.android.systemui.statusbar.policy.DevicePostureController;
+import com.android.systemui.statusbar.policy.DevicePostureControllerImpl;
import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.ExtensionControllerImpl;
import com.android.systemui.statusbar.policy.FlashlightController;
@@ -130,6 +132,11 @@
AccessPointControllerImpl accessPointControllerImpl);
/** */
+ @Binds
+ DevicePostureController provideDevicePostureController(
+ DevicePostureControllerImpl devicePostureControllerImpl);
+
+ /** */
@SysUISingleton
@Provides
static AccessPointControllerImpl provideAccessPointControllerImpl(
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
new file mode 100644
index 0000000..8e7c49a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
@@ -0,0 +1,127 @@
+/*
+ * 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.unfold
+
+import android.content.Context
+import android.graphics.PixelFormat
+import android.hardware.devicestate.DeviceStateManager
+import android.hardware.devicestate.DeviceStateManager.FoldStateListener
+import android.view.Surface
+import android.view.WindowManager
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.unfold.UnfoldTransitionProgressProvider
+import com.android.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.systemui.statusbar.LightRevealScrim
+import com.android.systemui.statusbar.LinearLightRevealEffect
+import java.util.concurrent.Executor
+import java.util.function.Consumer
+import javax.inject.Inject
+
+@SysUISingleton
+class UnfoldLightRevealOverlayAnimation @Inject constructor(
+ private val context: Context,
+ private val deviceStateManager: DeviceStateManager,
+ private val unfoldTransitionProgressProvider: UnfoldTransitionProgressProvider,
+ @Main private val executor: Executor,
+ private val windowManager: WindowManager
+) {
+
+ private val transitionListener = TransitionListener()
+ private var scrimView: LightRevealScrim? = null
+
+ fun init() {
+ deviceStateManager.registerCallback(executor, FoldListener())
+ unfoldTransitionProgressProvider.addCallback(transitionListener)
+ }
+
+ private inner class TransitionListener : TransitionProgressListener {
+
+ override fun onTransitionProgress(progress: Float) {
+ scrimView?.revealAmount = progress
+ }
+
+ override fun onTransitionFinished() {
+ removeOverlayView()
+ }
+
+ override fun onTransitionStarted() {
+ }
+ }
+
+ private inner class FoldListener : FoldStateListener(context, Consumer { isFolded ->
+ if (isFolded) {
+ removeOverlayView()
+ } else {
+ // Add overlay view before starting the transition as soon as we unfolded the device
+ addOverlayView()
+ }
+ })
+
+ private fun addOverlayView() {
+ val params: WindowManager.LayoutParams = WindowManager.LayoutParams()
+ params.height = WindowManager.LayoutParams.MATCH_PARENT
+ params.width = WindowManager.LayoutParams.MATCH_PARENT
+ params.format = PixelFormat.TRANSLUCENT
+
+ // TODO(b/193801466): create a separate type for this overlay
+ params.type = WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY
+ params.title = "Unfold Light Reveal Animation"
+ params.layoutInDisplayCutoutMode =
+ WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+ params.fitInsetsTypes = 0
+ params.flags = (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
+ params.setTrustedOverlay()
+
+ val rotation = windowManager.defaultDisplay.rotation
+ val isVerticalFold = rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180
+
+ val newScrimView = LightRevealScrim(context, null)
+ .apply {
+ revealEffect = LinearLightRevealEffect(isVerticalFold)
+ revealAmountListener = Consumer {}
+ revealAmount = 0f
+ }
+
+ val packageName: String = newScrimView.context.opPackageName
+ params.packageName = packageName
+ params.hideTimeoutMilliseconds = OVERLAY_HIDE_TIMEOUT_MILLIS
+
+ if (scrimView?.parent != null) {
+ windowManager.removeView(scrimView)
+ }
+
+ this.scrimView = newScrimView
+
+ try {
+ windowManager.addView(scrimView, params)
+ } catch (e: WindowManager.BadTokenException) {
+ e.printStackTrace()
+ }
+ }
+
+ private fun removeOverlayView() {
+ scrimView?.let {
+ if (it.parent != null) {
+ windowManager.removeViewImmediate(it)
+ }
+ scrimView = null
+ }
+ }
+}
+
+private const val OVERLAY_HIDE_TIMEOUT_MILLIS = 10_000L
diff --git a/packages/SystemUI/src/com/android/systemui/util/ViewController.java b/packages/SystemUI/src/com/android/systemui/util/ViewController.java
index 0dd5788..32bbe1c 100644
--- a/packages/SystemUI/src/com/android/systemui/util/ViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/ViewController.java
@@ -110,6 +110,16 @@
}
/**
+ * Destroys this controller so that it never receives view attach and detach events again.
+ * Does nothing if the view is null.
+ */
+ public void destroy() {
+ if (mView != null) {
+ mView.removeOnAttachStateChangeListener(mOnAttachStateListener);
+ }
+ }
+
+ /**
* Called when the view is attached and a call to {@link #init()} has been made in either order.
*/
protected abstract void onViewAttached();
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index f2db4f1..db965db 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -242,6 +242,11 @@
void initSplitScreen(SplitScreen splitScreen) {
mSplitScreenKeyguardCallback = new KeyguardUpdateMonitorCallback() {
@Override
+ public void onKeyguardVisibilityChanged(boolean showing) {
+ splitScreen.onKeyguardVisibilityChanged(showing);
+ }
+
+ @Override
public void onKeyguardOccludedChanged(boolean occluded) {
splitScreen.onKeyguardOccludedChanged(occluded);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index e9061af..ec4dfba 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -513,7 +513,7 @@
public void testTriesToAuthenticate_whenBouncer() {
setKeyguardBouncerVisibility(true);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
verify(mFaceManager).isHardwareDetected();
verify(mFaceManager).hasEnrolledTemplates(anyInt());
}
@@ -523,7 +523,7 @@
mKeyguardUpdateMonitor.dispatchStartedWakingUp();
mTestableLooper.processAllMessages();
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
}
@Test
@@ -533,7 +533,8 @@
mTestableLooper.processAllMessages();
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyBoolean());
}
@Test
@@ -545,7 +546,8 @@
mKeyguardUpdateMonitor.dispatchStartedWakingUp();
mTestableLooper.processAllMessages();
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyBoolean());
}
@Test
@@ -568,13 +570,14 @@
mKeyguardUpdateMonitor.dispatchStartedWakingUp();
mTestableLooper.processAllMessages();
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
// Stop scanning when bouncer becomes visible
setKeyguardBouncerVisibility(true);
clearInvocations(mFaceManager);
mKeyguardUpdateMonitor.requestFaceAuth(true);
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyBoolean());
}
@Test
@@ -582,7 +585,7 @@
mKeyguardUpdateMonitor.setKeyguardOccluded(true);
mKeyguardUpdateMonitor.setAssistantVisible(true);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
}
@Test
@@ -594,7 +597,7 @@
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */,
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */);
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
}
@Test
@@ -604,7 +607,8 @@
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */,
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */);
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyBoolean());
}
@Test
@@ -615,7 +619,8 @@
KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyBoolean());
}
@Test
@@ -626,7 +631,7 @@
KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT);
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
}
@Test
@@ -638,7 +643,8 @@
mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true);
mTestableLooper.processAllMessages();
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any());
+ verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyBoolean());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 8c53091..ad16e9d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -54,6 +54,7 @@
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.AutoTileManager;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.Clock;
@@ -91,6 +92,8 @@
@Mock
private MediaHost mQQSMediaHost;
@Mock
+ private KeyguardBypassController mBypassController;
+ @Mock
private FalsingManager mFalsingManager;
public QSFragmentTest() {
@@ -181,6 +184,7 @@
new QSDetailDisplayer(),
mQSMediaHost,
mQQSMediaHost,
+ mBypassController,
mQsComponentFactory,
mFalsingManager);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index d5a2919..be7917a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -33,7 +33,7 @@
import android.hardware.biometrics.PromptInfo;
import android.hardware.fingerprint.IUdfpsHbmListener;
import android.os.Bundle;
-import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
@@ -125,25 +125,25 @@
public void testOnSystemBarAttributesChanged() {
doTestOnSystemBarAttributesChanged(DEFAULT_DISPLAY, 1,
new AppearanceRegion[]{new AppearanceRegion(2, new Rect())}, false,
- BEHAVIOR_DEFAULT, new InsetsState(), "test");
+ BEHAVIOR_DEFAULT, new InsetsVisibilities(), "test");
}
@Test
public void testOnSystemBarAttributesChangedForSecondaryDisplay() {
doTestOnSystemBarAttributesChanged(SECONDARY_DISPLAY, 1,
new AppearanceRegion[]{new AppearanceRegion(2, new Rect())}, false,
- BEHAVIOR_DEFAULT, new InsetsState(), "test");
+ BEHAVIOR_DEFAULT, new InsetsVisibilities(), "test");
}
private void doTestOnSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, InsetsState requestedState, String packageName) {
+ @Behavior int behavior, InsetsVisibilities requestedVisibilities, String packageName) {
mCommandQueue.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions,
- navbarColorManagedByIme, behavior, requestedState, packageName);
+ navbarColorManagedByIme, behavior, requestedVisibilities, packageName);
waitForIdleSync();
verify(mCallbacks).onSystemBarAttributesChanged(eq(displayId), eq(appearance),
eq(appearanceRegions), eq(navbarColorManagedByIme), eq(behavior),
- eq(requestedState), eq(packageName));
+ eq(requestedVisibilities), eq(packageName));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 298bd9a..f5ce673 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -81,6 +81,7 @@
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
import com.android.systemui.statusbar.phone.LockIcon;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -146,6 +147,8 @@
private LockPatternUtils mLockPatternUtils;
@Mock
private IActivityManager mIActivityManager;
+ @Mock
+ private KeyguardBypassController mKeyguardBypassController;
@Captor
private ArgumentCaptor<DockManager.AlignmentStateListener> mAlignmentListener;
@Captor
@@ -216,7 +219,8 @@
mController = new KeyguardIndicationController(mContext, mWakeLockBuilder,
mKeyguardStateController, mStatusBarStateController, mKeyguardUpdateMonitor,
mDockManager, mBroadcastDispatcher, mDevicePolicyManager, mIBatteryStats,
- mUserManager, mExecutor, mFalsingManager, mLockPatternUtils, mIActivityManager);
+ mUserManager, mExecutor, mFalsingManager, mLockPatternUtils, mIActivityManager,
+ mKeyguardBypassController);
mController.init();
mController.setIndicationArea(mIndicationArea);
verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
@@ -507,6 +511,7 @@
createController();
String message = mContext.getString(R.string.keyguard_retry);
when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
+ when(mKeyguardUpdateMonitor.isFaceEnrolled()).thenReturn(true);
mController.setVisible(true);
mController.getKeyguardCallback().onBiometricError(FaceManager.FACE_ERROR_TIMEOUT,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
index 7e771ce..a3569e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
@@ -31,7 +31,6 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -72,7 +71,6 @@
@Mock private HeadsUpViewBinder mHeadsUpViewBinder;
@Mock private NotificationInterruptStateProvider mNotificationInterruptStateProvider;
@Mock private NotificationRemoteInputManager mRemoteInputManager;
- @Mock private RemoteInputController mRemoteInputController;
@Mock private NotifLifetimeExtender.OnEndLifetimeExtensionCallback mEndLifetimeExtension;
@Mock private NodeController mHeaderController;
@@ -81,7 +79,6 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
mCoordinator = new HeadsUpCoordinator(
mHeadsUpManager,
@@ -215,7 +212,7 @@
// WHEN mEntry is removed from the notification collection
mCollectionListener.onEntryRemoved(mEntry, /* cancellation reason */ 0);
- when(mRemoteInputController.isSpinning(any())).thenReturn(false);
+ when(mRemoteInputManager.isSpinning(any())).thenReturn(false);
// THEN heads up manager should remove the entry
verify(mHeadsUpManager).removeNotification(mEntry.getKey(), false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 6ee2f20..c56d085 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -24,6 +24,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -128,7 +129,6 @@
@Mock private ForegroundServiceDungeonView mForegroundServiceDungeonView;
@Mock private LayoutInflater mLayoutInflater;
@Mock private NotificationRemoteInputManager mRemoteInputManager;
- @Mock private RemoteInputController mRemoteInputController;
@Mock private VisualStabilityManager mVisualStabilityManager;
@Mock private ShadeController mShadeController;
@@ -145,7 +145,6 @@
when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
when(mFgServicesSectionController.createView(mLayoutInflater))
.thenReturn(mForegroundServiceDungeonView);
- when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
mController = new NotificationStackScrollLayoutController(
true,
@@ -402,6 +401,19 @@
any(ForegroundServiceDungeonView.class));
}
+ @Test
+ public void testUpdateFooter_remoteInput() {
+ ArgumentCaptor<RemoteInputController.Callback> callbackCaptor =
+ ArgumentCaptor.forClass(RemoteInputController.Callback.class);
+ doNothing().when(mRemoteInputManager).addControllerCallback(callbackCaptor.capture());
+ when(mRemoteInputManager.isRemoteInputActive()).thenReturn(false);
+ mController.attach(mNotificationStackScrollLayout);
+ verify(mNotificationStackScrollLayout).setIsRemoteInputActive(false);
+ RemoteInputController.Callback callback = callbackCaptor.getValue();
+ callback.onRemoteInputActive(true);
+ verify(mNotificationStackScrollLayout).setIsRemoteInputActive(true);
+ }
+
private LogMaker logMatcher(int category, int type) {
return argThat(new LogMatcher(category, type));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 6185437..d02d77e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -52,10 +52,9 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.EmptyShadeView;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationShelfController;
-import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -96,13 +95,10 @@
@Mock private NotificationGroupManagerLegacy mGroupExpansionManager;
@Mock private ExpandHelper mExpandHelper;
@Mock private EmptyShadeView mEmptyShadeView;
- @Mock private NotificationRemoteInputManager mRemoteInputManager;
- @Mock private RemoteInputController mRemoteInputController;
@Mock private NotificationRoundnessManager mNotificationRoundnessManager;
@Mock private KeyguardBypassController mBypassController;
@Mock private NotificationSectionsManager mNotificationSectionsManager;
@Mock private NotificationSection mNotificationSection;
- @Mock private SysuiStatusBarStateController mStatusBarStateController;
@Mock private NotificationSwipeHelper mNotificationSwipeHelper;
@Mock private NotificationStackScrollLayoutController mStackScrollLayoutController;
@Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
@@ -127,7 +123,6 @@
new NotificationSection[]{
mNotificationSection
});
- when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
// Interact with real instance of AmbientState.
mAmbientState = new AmbientState(mContext, mNotificationSectionsManager, mBypassController);
@@ -153,7 +148,6 @@
when(mStackScrollLayoutController.getNoticationRoundessManager())
.thenReturn(mNotificationRoundnessManager);
mStackScroller.setController(mStackScrollLayoutController);
- mStackScroller.setRemoteInputManager(mRemoteInputManager);
// Stub out functionality that isn't necessary to test.
doNothing().when(mBar)
@@ -301,7 +295,7 @@
when(row.canViewBeDismissed()).thenReturn(true);
when(mStackScroller.getChildCount()).thenReturn(1);
when(mStackScroller.getChildAt(anyInt())).thenReturn(row);
- when(mRemoteInputController.isRemoteInputActive()).thenReturn(true);
+ mStackScroller.setIsRemoteInputActive(true);
when(mStackScrollLayoutController.hasActiveClearableNotifications(ROWS_ALL))
.thenReturn(true);
when(mStackScrollLayoutController.hasActiveNotifications()).thenReturn(true);
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 32b08be..b0d1fc1 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
@@ -39,10 +39,14 @@
import com.android.systemui.SysuiBaseFragmentTest;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.policy.NetworkController;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
@@ -54,13 +58,19 @@
@SmallTest
public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
- private StatusBar mStatusBar;
private NotificationIconAreaController mMockNotificationAreaController;
private View mNotificationAreaInner;
- private StatusBarStateController mStatusBarStateController;
private OngoingCallController mOngoingCallController;
private SystemStatusAnimationScheduler mAnimationScheduler;
private StatusBarLocationPublisher mLocationPublisher;
+ // Set in instantiate()
+ private StatusBarIconController mStatusBarIconController;
+ private NetworkController mNetworkController;
+ private StatusBarStateController mStatusBarStateController;
+ private KeyguardStateController mKeyguardStateController;
+
+ private final StatusBar mStatusBar = mock(StatusBar.class);
+ private final CommandQueue mCommandQueue = mock(CommandQueue.class);
public CollapsedStatusBarFragmentTest() {
super(CollapsedStatusBarFragment.class);
@@ -68,7 +78,6 @@
@Before
public void setup() {
- mStatusBar = mock(StatusBar.class);
mStatusBarStateController = mDependency
.injectMockDependency(StatusBarStateController.class);
injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
@@ -204,6 +213,7 @@
mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
}
+ @Ignore("b/192618546")
@Test
public void testOnDozingChanged() throws Exception {
mFragments.dispatchResume();
@@ -227,6 +237,10 @@
mOngoingCallController = mock(OngoingCallController.class);
mAnimationScheduler = mock(SystemStatusAnimationScheduler.class);
mLocationPublisher = mock(StatusBarLocationPublisher.class);
+ mStatusBarIconController = mock(StatusBarIconController.class);
+ mNetworkController = mock(NetworkController.class);
+ mStatusBarStateController = mock(StatusBarStateController.class);
+ mKeyguardStateController = mock(KeyguardStateController.class);
setUpNotificationIconAreaController();
return new CollapsedStatusBarFragment(
mOngoingCallController,
@@ -234,7 +248,12 @@
mLocationPublisher,
mMockNotificationAreaController,
mock(FeatureFlags.class),
- () -> Optional.of(mStatusBar));
+ () -> Optional.of(mStatusBar),
+ mStatusBarIconController,
+ mKeyguardStateController,
+ mNetworkController,
+ mStatusBarStateController,
+ mCommandQueue);
}
private void setUpNotificationIconAreaController() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
new file mode 100644
index 0000000..217a77d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.view.ViewGroup;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.keyguard.CarrierTextController;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.UserInfoController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
+ @Mock
+ private KeyguardStatusBarView mKeyguardStatusBarView;
+ @Mock
+ private ViewGroup mViewGroup;
+ @Mock
+ private CarrierTextController mCarrierTextController;
+ @Mock
+ private ConfigurationController mConfigurationController;
+ @Mock
+ private SystemStatusAnimationScheduler mAnimationScheduler;
+ @Mock
+ private BatteryController mBatteryController;
+ @Mock
+ private UserInfoController mUserInfoController;
+ @Mock
+ private StatusBarIconController mStatusBarIconController;
+ @Mock
+ private FeatureFlags mFeatureFlags;
+
+ private KeyguardStatusBarViewController mController;
+
+ @Before
+ public void setup() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ when(mKeyguardStatusBarView.getResources()).thenReturn(mContext.getResources());
+ when(mKeyguardStatusBarView.findViewById(R.id.statusIcons)).thenReturn(mViewGroup);
+ when(mViewGroup.getContext()).thenReturn(mContext);
+
+ mController = new KeyguardStatusBarViewController(
+ mKeyguardStatusBarView,
+ mCarrierTextController,
+ mConfigurationController,
+ mAnimationScheduler,
+ mBatteryController,
+ mUserInfoController,
+ mStatusBarIconController,
+ new StatusBarIconController.TintedIconManager.Factory(mFeatureFlags)
+ );
+ }
+
+ @Test
+ public void onViewAttached_callbacksRegistered() {
+ mController.onViewAttached();
+
+ verify(mConfigurationController).addCallback(any());
+ verify(mAnimationScheduler).addCallback(any());
+ verify(mUserInfoController).addCallback(any());
+ verify(mStatusBarIconController).addIconGroup(any());
+ }
+
+ @Test
+ public void onViewDetached_callbacksUnregistered() {
+ // Set everything up first.
+ mController.onViewAttached();
+
+ mController.onViewDetached();
+
+ verify(mConfigurationController).removeCallback(any());
+ verify(mAnimationScheduler).removeCallback(any());
+ verify(mUserInfoController).removeCallback(any());
+ verify(mStatusBarIconController).removeIconGroup(any());
+ }
+
+ @Test
+ public void setBatteryListening_true_callbackAdded() {
+ mController.setBatteryListening(true);
+
+ verify(mBatteryController).addCallback(any());
+ }
+
+ @Test
+ public void setBatteryListening_false_callbackRemoved() {
+ // First set to true so that we know setting to false is a change in state.
+ mController.setBatteryListening(true);
+
+ mController.setBatteryListening(false);
+
+ verify(mBatteryController).removeCallback(any());
+ }
+
+ @Test
+ public void setBatteryListening_trueThenTrue_callbackAddedOnce() {
+ mController.setBatteryListening(true);
+ mController.setBatteryListening(true);
+
+ verify(mBatteryController).addCallback(any());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
index c3adee9..74f08ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
@@ -102,7 +102,7 @@
null /* appearanceRegions */,
false /* navbarColorManagedByIme */,
BEHAVIOR_DEFAULT,
- null /* requestedState */,
+ null /* requestedVisibilities */,
null /* packageName */);
assertTrue(mLightsOutNotifController.areLightsOut());
}
@@ -115,7 +115,7 @@
null /* appearanceRegions */,
false /* navbarColorManagedByIme */,
BEHAVIOR_DEFAULT,
- null /* requestedState */,
+ null /* requestedVisibilities */,
null /* packageName */);
assertFalse(mLightsOutNotifController.areLightsOut());
}
@@ -146,7 +146,7 @@
null /* appearanceRegions */,
false /* navbarColorManagedByIme */,
BEHAVIOR_DEFAULT,
- null /* requestedState */,
+ null /* requestedVisibilities */,
null /* packageName */);
// THEN we should show dot
@@ -166,7 +166,7 @@
null /* appearanceRegions */,
false /* navbarColorManagedByIme */,
BEHAVIOR_DEFAULT,
- null /* requestedState */,
+ null /* requestedVisibilities */,
null /* packageName */);
// THEN we shouldn't show the dot
@@ -186,7 +186,7 @@
null /* appearanceRegions */,
false /* navbarColorManagedByIme */,
BEHAVIOR_DEFAULT,
- null /* requestedState */,
+ null /* requestedVisibilities */,
null /* packageName */);
// THEN we shouldn't show the dot
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index a8a1b8b..cbaca3a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -88,6 +88,7 @@
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.controls.dagger.ControlsComponent;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentService;
@@ -107,7 +108,6 @@
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.PulseExpansionHandler;
-import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
@@ -297,9 +297,9 @@
@Mock
private NotificationRemoteInputManager mNotificationRemoteInputManager;
@Mock
- private RemoteInputController mRemoteInputController;
- @Mock
private RecordingController mRecordingController;
+ @Mock
+ private ControlsComponent mControlsComponent;
private SysuiStatusBarStateController mStatusBarStateController;
private NotificationPanelViewController mNotificationPanelViewController;
@@ -372,16 +372,17 @@
mKeyguardBypassController,
mDozeParameters,
mUnlockedScreenOffAnimationController);
+ mConfigurationController = new ConfigurationControllerImpl(mContext);
PulseExpansionHandler expansionHandler = new PulseExpansionHandler(
mContext,
coordinator,
mKeyguardBypassController, mHeadsUpManager,
mock(NotificationRoundnessManager.class),
+ mConfigurationController,
mStatusBarStateController,
mFalsingManager,
mLockscreenShadeTransitionController,
new FalsingCollectorFake());
- mConfigurationController = new ConfigurationControllerImpl(mContext);
when(mKeyguardStatusViewComponentFactory.build(any()))
.thenReturn(mKeyguardStatusViewComponent);
when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())
@@ -396,8 +397,7 @@
.thenReturn(mKeyguardStatusView);
when(mLayoutInflater.inflate(eq(R.layout.keyguard_bottom_area), any(), anyBoolean()))
.thenReturn(mKeyguardBottomArea);
- when(mNotificationRemoteInputManager.getController()).thenReturn(mRemoteInputController);
- when(mRemoteInputController.isRemoteInputActive()).thenReturn(false);
+ when(mNotificationRemoteInputManager.isRemoteInputActive()).thenReturn(false);
reset(mView);
@@ -443,7 +443,8 @@
mSecureSettings,
mSplitShadeHeaderController,
mUnlockedScreenOffAnimationController,
- mNotificationRemoteInputManager);
+ mNotificationRemoteInputManager,
+ mControlsComponent);
mNotificationPanelViewController.initDependencies(
mStatusBar,
mNotificationShelfController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
index 4796cd7..10eb71f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
@@ -47,7 +47,8 @@
@Test
fun testGetBoundingRectForPrivacyChipForRotation_noCutout() {
val screenBounds = Rect(0, 0, 1080, 2160)
- val roundedCornerPadding = 20
+ val minLeftPadding = 20
+ val minRightPadding = 20
val sbHeightPortrait = 100
val sbHeightLandscape = 60
val currentRotation = ROTATION_NONE
@@ -64,7 +65,8 @@
null,
windowMetrics,
sbHeightPortrait,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
var chipBounds = getPrivacyChipBoundingRectForInsets(bounds, dotWidth, chipWidth, isRtl)
/* 1080 - 20 (rounded corner) - 30 (chip),
@@ -92,7 +94,8 @@
dc,
windowMetrics,
sbHeightLandscape,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
chipBounds = getPrivacyChipBoundingRectForInsets(bounds, dotWidth, chipWidth, isRtl)
/* 2160 - 20 (rounded corner) - 30 (chip),
@@ -118,7 +121,8 @@
// GIVEN a device in portrait mode with width < height and a display cutout in the top-left
val screenBounds = Rect(0, 0, 1080, 2160)
val dcBounds = Rect(0, 0, 100, 100)
- val roundedCornerPadding = 20
+ val minLeftPadding = 20
+ val minRightPadding = 20
val sbHeightPortrait = 100
val sbHeightLandscape = 60
val currentRotation = ROTATION_NONE
@@ -131,7 +135,7 @@
var targetRotation = ROTATION_NONE
var expectedBounds = Rect(dcBounds.right,
0,
- screenBounds.right - roundedCornerPadding,
+ screenBounds.right - minRightPadding,
sbHeightPortrait)
var bounds = calculateInsetsForRotationWithRotatedResources(
@@ -140,14 +144,15 @@
dc,
windowMetrics,
sbHeightPortrait,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
targetRotation = ROTATION_LANDSCAPE
expectedBounds = Rect(dcBounds.height(),
0,
- screenBounds.height() - roundedCornerPadding,
+ screenBounds.height() - minRightPadding,
sbHeightLandscape)
bounds = calculateInsetsForRotationWithRotatedResources(
@@ -156,16 +161,17 @@
dc,
windowMetrics,
sbHeightLandscape,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
// THEN the side that does NOT share a short side with the display cutout ignores the
// display cutout bounds
targetRotation = ROTATION_UPSIDE_DOWN
- expectedBounds = Rect(roundedCornerPadding,
+ expectedBounds = Rect(minLeftPadding,
0,
- screenBounds.width() - roundedCornerPadding,
+ screenBounds.width() - minRightPadding,
sbHeightPortrait)
bounds = calculateInsetsForRotationWithRotatedResources(
@@ -174,13 +180,14 @@
dc,
windowMetrics,
sbHeightPortrait,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
// Phone in portrait, seascape (rot_270) bounds
targetRotation = ROTATION_SEASCAPE
- expectedBounds = Rect(roundedCornerPadding,
+ expectedBounds = Rect(minLeftPadding,
0,
screenBounds.height() - dcBounds.height(),
sbHeightLandscape)
@@ -191,7 +198,8 @@
dc,
windowMetrics,
sbHeightLandscape,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
}
@@ -205,7 +213,8 @@
val screenBounds = Rect(0, 0, 1080, 2160)
// cutout centered at the top
val dcBounds = Rect(490, 0, 590, 100)
- val roundedCornerPadding = 20
+ val minLeftPadding = 20
+ val minRightPadding = 20
val sbHeightPortrait = 100
val sbHeightLandscape = 60
val currentRotation = ROTATION_NONE
@@ -216,9 +225,9 @@
// THEN only the landscape/seascape rotations should avoid the cutout area because of the
// potential letterboxing
var targetRotation = ROTATION_NONE
- var expectedBounds = Rect(roundedCornerPadding,
+ var expectedBounds = Rect(minLeftPadding,
0,
- screenBounds.right - roundedCornerPadding,
+ screenBounds.right - minRightPadding,
sbHeightPortrait)
var bounds = calculateInsetsForRotationWithRotatedResources(
@@ -227,14 +236,15 @@
dc,
windowMetrics,
sbHeightPortrait,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
targetRotation = ROTATION_LANDSCAPE
expectedBounds = Rect(dcBounds.height(),
0,
- screenBounds.height() - roundedCornerPadding,
+ screenBounds.height() - minRightPadding,
sbHeightLandscape)
bounds = calculateInsetsForRotationWithRotatedResources(
@@ -243,14 +253,15 @@
dc,
windowMetrics,
sbHeightLandscape,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
targetRotation = ROTATION_UPSIDE_DOWN
- expectedBounds = Rect(roundedCornerPadding,
+ expectedBounds = Rect(minLeftPadding,
0,
- screenBounds.right - roundedCornerPadding,
+ screenBounds.right - minRightPadding,
sbHeightPortrait)
bounds = calculateInsetsForRotationWithRotatedResources(
@@ -259,12 +270,13 @@
dc,
windowMetrics,
sbHeightPortrait,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
targetRotation = ROTATION_SEASCAPE
- expectedBounds = Rect(roundedCornerPadding,
+ expectedBounds = Rect(minLeftPadding,
0,
screenBounds.height() - dcBounds.height(),
sbHeightLandscape)
@@ -275,7 +287,8 @@
dc,
windowMetrics,
sbHeightLandscape,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
}
@@ -285,7 +298,8 @@
// GIVEN device in portrait mode, where width < height and no cutout
val currentRotation = ROTATION_NONE
val screenBounds = Rect(0, 0, 1080, 2160)
- val roundedCornerPadding = 20
+ val minLeftPadding = 20
+ val minRightPadding = 20
val sbHeightPortrait = 100
val sbHeightLandscape = 60
@@ -293,9 +307,9 @@
// THEN content insets should only use rounded corner padding
var targetRotation = ROTATION_NONE
- var expectedBounds = Rect(roundedCornerPadding,
+ var expectedBounds = Rect(minLeftPadding,
0,
- screenBounds.right - roundedCornerPadding,
+ screenBounds.right - minRightPadding,
sbHeightPortrait)
var bounds = calculateInsetsForRotationWithRotatedResources(
@@ -304,13 +318,14 @@
null, /* no cutout */
windowMetrics,
sbHeightPortrait,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
targetRotation = ROTATION_LANDSCAPE
- expectedBounds = Rect(roundedCornerPadding,
+ expectedBounds = Rect(minLeftPadding,
0,
- screenBounds.height() - roundedCornerPadding,
+ screenBounds.height() - minRightPadding,
sbHeightLandscape)
bounds = calculateInsetsForRotationWithRotatedResources(
@@ -319,13 +334,14 @@
null, /* no cutout */
windowMetrics,
sbHeightLandscape,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
targetRotation = ROTATION_UPSIDE_DOWN
- expectedBounds = Rect(roundedCornerPadding,
+ expectedBounds = Rect(minLeftPadding,
0,
- screenBounds.width() - roundedCornerPadding,
+ screenBounds.width() - minRightPadding,
sbHeightPortrait)
bounds = calculateInsetsForRotationWithRotatedResources(
@@ -334,13 +350,14 @@
null, /* no cutout */
windowMetrics,
sbHeightPortrait,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
targetRotation = ROTATION_LANDSCAPE
- expectedBounds = Rect(roundedCornerPadding,
+ expectedBounds = Rect(minLeftPadding,
0,
- screenBounds.height() - roundedCornerPadding,
+ screenBounds.height() - minRightPadding,
sbHeightLandscape)
bounds = calculateInsetsForRotationWithRotatedResources(
@@ -349,7 +366,41 @@
null, /* no cutout */
windowMetrics,
sbHeightLandscape,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+ }
+
+ @Test
+ fun testMinLeftRight_accountsForDisplayCutout() {
+ // GIVEN a device in portrait mode with width < height and a display cutout in the top-left
+ val screenBounds = Rect(0, 0, 1080, 2160)
+ val dcBounds = Rect(0, 0, 100, 100)
+ val minLeftPadding = 80
+ val minRightPadding = 150
+ val sbHeightPortrait = 100
+ val sbHeightLandscape = 60
+ val currentRotation = ROTATION_NONE
+
+ `when`(windowMetrics.bounds).thenReturn(screenBounds)
+ `when`(dc.boundingRects).thenReturn(listOf(dcBounds))
+
+ // THEN left should be set to the display cutout width, and right should use the minRight
+ var targetRotation = ROTATION_NONE
+ var expectedBounds = Rect(dcBounds.right,
+ 0,
+ screenBounds.right - minRightPadding,
+ sbHeightPortrait)
+
+ var bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ dc,
+ windowMetrics,
+ sbHeightPortrait,
+ minLeftPadding,
+ minRightPadding)
+
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 37a6d21..83bf96b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -61,7 +61,6 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -111,8 +110,6 @@
@Mock
private NotificationRemoteInputManager mRemoteInputManager;
@Mock
- private RemoteInputController mRemoteInputController;
- @Mock
private StatusBar mStatusBar;
@Mock
private KeyguardStateController mKeyguardStateController;
@@ -153,8 +150,6 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
-
when(mContentIntent.isActivity()).thenReturn(true);
when(mContentIntent.getCreatorUserHandle()).thenReturn(UserHandle.of(1));
when(mContentIntent.getIntent()).thenReturn(mContentIntentInner);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index ce45f26..fd85c44 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -46,7 +46,6 @@
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
-import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -89,8 +88,6 @@
public void setup() {
NotificationRemoteInputManager notificationRemoteInputManager =
mock(NotificationRemoteInputManager.class);
- when(notificationRemoteInputManager.getController())
- .thenReturn(mock(RemoteInputController.class));
mMetricsLogger = new FakeMetricsLogger();
mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
mCommandQueue = new CommandQueue(mContext);
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 c504fd8..2a58f7c 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
@@ -98,6 +98,7 @@
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.settings.brightness.BrightnessSlider;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.unfold.config.UnfoldTransitionConfig;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -110,7 +111,6 @@
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.PulseExpansionHandler;
-import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
@@ -146,6 +146,7 @@
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.volume.VolumeComponent;
@@ -201,7 +202,6 @@
@Mock private KeyguardViewMediator mKeyguardViewMediator;
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
@Mock private NotificationRemoteInputManager mRemoteInputManager;
- @Mock private RemoteInputController mRemoteInputController;
@Mock private StatusBarStateControllerImpl mStatusBarStateController;
@Mock private BatteryController mBatteryController;
@Mock private DeviceProvisionedController mDeviceProvisionedController;
@@ -266,9 +266,12 @@
@Mock private Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
@Mock private BrightnessSlider.Factory mBrightnessSliderFactory;
@Mock private WiredChargingRippleController mWiredChargingRippleController;
+ @Mock private UnfoldTransitionConfig mUnfoldTransitionConfig;
+ @Mock private Lazy<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealOverlayAnimationLazy;
@Mock private OngoingCallController mOngoingCallController;
@Mock private SystemStatusAnimationScheduler mAnimationScheduler;
@Mock private StatusBarLocationPublisher mLocationPublisher;
+ @Mock private StatusBarIconController mIconController;
@Mock private LockscreenShadeTransitionController mLockscreenTransitionController;
@Mock private FeatureFlags mFeatureFlags;
@Mock private IWallpaperManager mWallpaperManager;
@@ -331,8 +334,6 @@
return null;
}).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any());
- when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
-
WakefulnessLifecycle wakefulnessLifecycle =
new WakefulnessLifecycle(mContext, mWallpaperManager);
wakefulnessLifecycle.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
@@ -439,9 +440,12 @@
mNotificationIconAreaController,
mBrightnessSliderFactory,
mWiredChargingRippleController,
+ mUnfoldTransitionConfig,
+ mUnfoldLightRevealOverlayAnimationLazy,
mOngoingCallController,
mAnimationScheduler,
mLocationPublisher,
+ mIconController,
mLockscreenTransitionController,
mFeatureFlags,
mKeyguardUnlockAnimationController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
new file mode 100644
index 0000000..ace2c71
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
@@ -0,0 +1,257 @@
+/*
+ * 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.policy
+
+import android.app.IActivityTaskManager
+import android.content.Context
+import android.content.DialogInterface
+import android.content.Intent
+import android.content.pm.UserInfo
+import android.graphics.Bitmap
+import android.hardware.face.FaceManager
+import android.hardware.fingerprint.FingerprintManager
+import android.os.Handler
+import android.os.UserHandle
+import android.os.UserManager
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.internal.util.UserIcons
+import com.android.systemui.GuestResumeSessionReceiver
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.qs.QSUserSwitcherEvent
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.telephony.TelephonyListenerManager
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.time.FakeSystemClock
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotNull
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.anyString
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+class UserSwitcherControllerTest : SysuiTestCase() {
+ @Mock private lateinit var keyguardStateController: KeyguardStateController
+ @Mock private lateinit var handler: Handler
+ @Mock private lateinit var userTracker: UserTracker
+ @Mock private lateinit var userManager: UserManager
+ @Mock private lateinit var activityStarter: ActivityStarter
+ @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
+ @Mock private lateinit var activityTaskManager: IActivityTaskManager
+ @Mock private lateinit var userDetailAdapter: UserSwitcherController.UserDetailAdapter
+ @Mock private lateinit var telephonyListenerManager: TelephonyListenerManager
+ @Mock private lateinit var secureSettings: SecureSettings
+ @Mock private lateinit var falsingManager: FalsingManager
+ private lateinit var testableLooper: TestableLooper
+ private lateinit var uiBgExecutor: FakeExecutor
+ private lateinit var uiEventLogger: UiEventLoggerFake
+ private lateinit var userSwitcherController: UserSwitcherController
+ private lateinit var picture: Bitmap
+ private val ownerId = UserHandle.USER_SYSTEM
+ private val ownerInfo = UserInfo(ownerId, "Owner", null,
+ UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL or UserInfo.FLAG_INITIALIZED or
+ UserInfo.FLAG_PRIMARY or UserInfo.FLAG_SYSTEM,
+ UserManager.USER_TYPE_FULL_SYSTEM)
+ private val guestId = 1234
+ private val guestInfo = UserInfo(guestId, "Guest", null,
+ UserInfo.FLAG_FULL or UserInfo.FLAG_GUEST, UserManager.USER_TYPE_FULL_GUEST)
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ testableLooper = TestableLooper.get(this)
+ uiBgExecutor = FakeExecutor(FakeSystemClock())
+ uiEventLogger = UiEventLoggerFake()
+
+ context.orCreateTestableResources.addOverride(
+ com.android.internal.R.bool.config_guestUserAutoCreated, false)
+
+ context.addMockSystemService(Context.FACE_SERVICE, mock(FaceManager::class.java))
+ context.addMockSystemService(Context.FINGERPRINT_SERVICE,
+ mock(FingerprintManager::class.java))
+
+ `when`(userManager.canAddMoreUsers()).thenReturn(true)
+
+ userSwitcherController = UserSwitcherController(context,
+ userManager,
+ userTracker,
+ keyguardStateController,
+ handler,
+ activityStarter,
+ broadcastDispatcher,
+ uiEventLogger,
+ falsingManager,
+ telephonyListenerManager,
+ activityTaskManager,
+ userDetailAdapter,
+ secureSettings,
+ uiBgExecutor)
+ userSwitcherController.mPauseRefreshUsers = true
+
+ picture = UserIcons.convertToBitmap(context.getDrawable(R.drawable.ic_avatar_user))
+ }
+
+ @Test
+ fun testAddGuest_okButtonPressed_isLogged() {
+ val emptyGuestUserRecord = UserSwitcherController.UserRecord(
+ null,
+ null,
+ true /* guest */,
+ false /* current */,
+ false /* isAddUser */,
+ false /* isRestricted */,
+ true /* isSwitchToEnabled */)
+ `when`(userTracker.userId).thenReturn(ownerId)
+ `when`(userTracker.userInfo).thenReturn(ownerInfo)
+
+ `when`(userManager.createGuest(any(), anyString())).thenReturn(guestInfo)
+
+ userSwitcherController.onUserListItemClicked(emptyGuestUserRecord)
+ testableLooper.processAllMessages()
+ assertEquals(1, uiEventLogger.numLogs())
+ assertEquals(QSUserSwitcherEvent.QS_USER_GUEST_ADD.id, uiEventLogger.eventId(0))
+ }
+
+ @Test
+ fun testRemoveGuest_removeButtonPressed_isLogged() {
+ val currentGuestUserRecord = UserSwitcherController.UserRecord(
+ guestInfo,
+ picture,
+ true /* guest */,
+ true /* current */,
+ false /* isAddUser */,
+ false /* isRestricted */,
+ true /* isSwitchToEnabled */)
+ `when`(userTracker.userId).thenReturn(guestInfo.id)
+ `when`(userTracker.userInfo).thenReturn(guestInfo)
+
+ userSwitcherController.onUserListItemClicked(currentGuestUserRecord)
+ assertNotNull(userSwitcherController.mExitGuestDialog)
+ userSwitcherController.mExitGuestDialog
+ .getButton(DialogInterface.BUTTON_POSITIVE).performClick()
+ testableLooper.processAllMessages()
+ assertEquals(1, uiEventLogger.numLogs())
+ assertEquals(QSUserSwitcherEvent.QS_USER_GUEST_REMOVE.id, uiEventLogger.eventId(0))
+ }
+
+ @Test
+ fun testRemoveGuest_cancelButtonPressed_isNotLogged() {
+ val currentGuestUserRecord = UserSwitcherController.UserRecord(
+ guestInfo,
+ picture,
+ true /* guest */,
+ true /* current */,
+ false /* isAddUser */,
+ false /* isRestricted */,
+ true /* isSwitchToEnabled */)
+ `when`(userTracker.userId).thenReturn(guestId)
+ `when`(userTracker.userInfo).thenReturn(guestInfo)
+
+ userSwitcherController.onUserListItemClicked(currentGuestUserRecord)
+ assertNotNull(userSwitcherController.mExitGuestDialog)
+ userSwitcherController.mExitGuestDialog
+ .getButton(DialogInterface.BUTTON_NEGATIVE).performClick()
+ testableLooper.processAllMessages()
+ assertEquals(0, uiEventLogger.numLogs())
+ }
+
+ @Test
+ fun testWipeGuest_startOverButtonPressed_isLogged() {
+ val currentGuestUserRecord = UserSwitcherController.UserRecord(
+ guestInfo,
+ picture,
+ true /* guest */,
+ false /* current */,
+ false /* isAddUser */,
+ false /* isRestricted */,
+ true /* isSwitchToEnabled */)
+ `when`(userTracker.userId).thenReturn(guestId)
+ `when`(userTracker.userInfo).thenReturn(guestInfo)
+
+ // Simulate that guest user has already logged in
+ `when`(secureSettings.getIntForUser(
+ eq(GuestResumeSessionReceiver.SETTING_GUEST_HAS_LOGGED_IN), anyInt(), anyInt()))
+ .thenReturn(1)
+
+ userSwitcherController.onUserListItemClicked(currentGuestUserRecord)
+
+ // Simulate a user switch event
+ val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, guestId)
+
+ assertNotNull(userSwitcherController.mGuestResumeSessionReceiver)
+ userSwitcherController.mGuestResumeSessionReceiver.onReceive(context, intent)
+
+ assertNotNull(userSwitcherController.mGuestResumeSessionReceiver.mNewSessionDialog)
+ userSwitcherController.mGuestResumeSessionReceiver.mNewSessionDialog
+ .getButton(GuestResumeSessionReceiver.ResetSessionDialog.BUTTON_WIPE).performClick()
+ testableLooper.processAllMessages()
+ assertEquals(1, uiEventLogger.numLogs())
+ assertEquals(QSUserSwitcherEvent.QS_USER_GUEST_WIPE.id, uiEventLogger.eventId(0))
+ }
+
+ @Test
+ fun testWipeGuest_continueButtonPressed_isLogged() {
+ val currentGuestUserRecord = UserSwitcherController.UserRecord(
+ guestInfo,
+ picture,
+ true /* guest */,
+ false /* current */,
+ false /* isAddUser */,
+ false /* isRestricted */,
+ true /* isSwitchToEnabled */)
+ `when`(userTracker.userId).thenReturn(guestId)
+ `when`(userTracker.userInfo).thenReturn(guestInfo)
+
+ // Simulate that guest user has already logged in
+ `when`(secureSettings.getIntForUser(
+ eq(GuestResumeSessionReceiver.SETTING_GUEST_HAS_LOGGED_IN), anyInt(), anyInt()))
+ .thenReturn(1)
+
+ userSwitcherController.onUserListItemClicked(currentGuestUserRecord)
+
+ // Simulate a user switch event
+ val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, guestId)
+
+ assertNotNull(userSwitcherController.mGuestResumeSessionReceiver)
+ userSwitcherController.mGuestResumeSessionReceiver.onReceive(context, intent)
+
+ assertNotNull(userSwitcherController.mGuestResumeSessionReceiver.mNewSessionDialog)
+ userSwitcherController.mGuestResumeSessionReceiver.mNewSessionDialog
+ .getButton(GuestResumeSessionReceiver.ResetSessionDialog.BUTTON_DONTWIPE)
+ .performClick()
+ testableLooper.processAllMessages()
+ assertEquals(1, uiEventLogger.numLogs())
+ assertEquals(QSUserSwitcherEvent.QS_USER_GUEST_CONTINUE.id, uiEventLogger.eventId(0))
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java
index f5ccac3..516eb6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java
@@ -33,4 +33,9 @@
@Override
public void notifyThemeChanged() {
}
+
+ @Override
+ public boolean isLayoutRtl() {
+ return false;
+ }
}
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index e336b6b..16645df 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -375,15 +375,38 @@
try {
FileChannel channel = getBlockOutputChannel();
+ // Format the data selectively.
+ //
+ // 1. write header, set length = 0
int header_size = DIGEST_SIZE_BYTES + HEADER_SIZE;
ByteBuffer buf = ByteBuffer.allocate(header_size);
buf.put(new byte[DIGEST_SIZE_BYTES]);
buf.putInt(PARTITION_TYPE_MARKER);
buf.putInt(0);
+ buf.flip();
channel.write(buf);
- // corrupt the payload explicitly
+ channel.force(true);
+
+ // 2. corrupt the legacy FRP data explicitly
int payload_size = (int) getBlockDeviceSize() - header_size;
- buf = ByteBuffer.allocate(payload_size);
+ buf = ByteBuffer.allocate(payload_size
+ - TEST_MODE_RESERVED_SIZE - FRP_CREDENTIAL_RESERVED_SIZE - 1);
+ channel.write(buf);
+ channel.force(true);
+
+ // 3. skip the test mode data and leave it unformat
+ // This is for a feature that enables testing.
+ channel.position(channel.position() + TEST_MODE_RESERVED_SIZE);
+
+ // 4. wipe the FRP_CREDENTIAL explicitly
+ buf = ByteBuffer.allocate(FRP_CREDENTIAL_RESERVED_SIZE);
+ channel.write(buf);
+ channel.force(true);
+
+ // 5. set unlock = 0 because it's a formatPartitionLocked
+ buf = ByteBuffer.allocate(FRP_CREDENTIAL_RESERVED_SIZE);
+ buf.put((byte)0);
+ buf.flip();
channel.write(buf);
channel.force(true);
} catch (IOException e) {
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index ac43fbd..019e4ea 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -232,14 +232,14 @@
public void onUserStarting(TargetUser user) {
if (mCurrentUser == -1) {
mCurrentUser = user.getUserIdentifier();
- setGlobalRestriction();
+ mSensorPrivacyServiceImpl.userSwitching(-1, user.getUserIdentifier());
}
}
@Override
public void onUserSwitching(TargetUser from, TargetUser to) {
mCurrentUser = to.getUserIdentifier();
- setGlobalRestriction();
+ mSensorPrivacyServiceImpl.userSwitching(from.getUserIdentifier(), to.getUserIdentifier());
}
class SensorPrivacyServiceImpl extends ISensorPrivacyManager.Stub implements
@@ -897,18 +897,22 @@
public boolean isIndividualSensorPrivacyEnabled(@UserIdInt int userId, int sensor) {
enforceObserveSensorPrivacyPermission();
synchronized (mLock) {
- SparseArray<SensorState> states = mIndividualEnabled.get(userId);
- if (states == null) {
- return false;
- }
- SensorState state = states.get(sensor);
- if (state == null) {
- return false;
- }
- return state.mEnabled;
+ return isIndividualSensorPrivacyEnabledLocked(userId, sensor);
}
}
+ private boolean isIndividualSensorPrivacyEnabledLocked(int userId, int sensor) {
+ SparseArray<SensorState> states = mIndividualEnabled.get(userId);
+ if (states == null) {
+ return false;
+ }
+ SensorState state = states.get(sensor);
+ if (state == null) {
+ return false;
+ }
+ return state.mEnabled;
+ }
+
/**
* Returns the state of sensor privacy from persistent storage.
*/
@@ -1149,11 +1153,27 @@
ISensorPrivacyListener listener) {
enforceObserveSensorPrivacyPermission();
if (listener == null) {
- throw new NullPointerException("listener cannot be null");
+ throw new IllegalArgumentException("listener cannot be null");
}
mHandler.addListener(userId, sensor, listener);
}
+
+ /**
+ * Registers a listener to be notified when the sensor privacy state changes. The callback
+ * can be called if the user changes and the setting is different between the transitioning
+ * users.
+ */
+ @Override
+ public void addUserGlobalIndividualSensorPrivacyListener(int sensor,
+ ISensorPrivacyListener listener) {
+ enforceObserveSensorPrivacyPermission();
+ if (listener == null) {
+ throw new IllegalArgumentException("listener cannot be null");
+ }
+ mHandler.addUserGlobalListener(sensor, listener);
+ }
+
/**
* Unregisters a listener from sensor privacy state change notifications.
*/
@@ -1174,12 +1194,22 @@
ISensorPrivacyListener listener) {
enforceObserveSensorPrivacyPermission();
if (listener == null) {
- throw new NullPointerException("listener cannot be null");
+ throw new IllegalArgumentException("listener cannot be null");
}
mHandler.removeListener(sensor, listener);
}
@Override
+ public void removeUserGlobalIndividualSensorPrivacyListener(int sensor,
+ ISensorPrivacyListener listener) {
+ enforceObserveSensorPrivacyPermission();
+ if (listener == null) {
+ throw new IllegalArgumentException("listener cannot be null");
+ }
+ mHandler.removeUserGlobalListener(sensor, listener);
+ }
+
+ @Override
public void suppressIndividualSensorPrivacyReminders(int userId, int sensor,
IBinder token, boolean suppress) {
enforceManageSensorPrivacyPermission();
@@ -1209,6 +1239,40 @@
}
}
+ private void userSwitching(int from, int to) {
+ boolean micState;
+ boolean camState;
+ boolean prevMicState;
+ boolean prevCamState;
+ synchronized (mLock) {
+ prevMicState = isIndividualSensorPrivacyEnabledLocked(from, MICROPHONE);
+ prevCamState = isIndividualSensorPrivacyEnabledLocked(from, CAMERA);
+ micState = isIndividualSensorPrivacyEnabledLocked(to, MICROPHONE);
+ camState = isIndividualSensorPrivacyEnabledLocked(to, CAMERA);
+ }
+ if (prevMicState != micState) {
+ mHandler.onUserGlobalSensorPrivacyChanged(MICROPHONE, micState);
+ setGlobalRestriction(MICROPHONE, micState);
+ }
+ if (prevCamState != camState) {
+ mHandler.onUserGlobalSensorPrivacyChanged(CAMERA, camState);
+ setGlobalRestriction(CAMERA, micState);
+ }
+ }
+
+ private void setGlobalRestriction(int sensor, boolean enabled) {
+ switch(sensor) {
+ case MICROPHONE:
+ mAppOpsManagerInternal.setGlobalRestriction(OP_RECORD_AUDIO, enabled,
+ mAppOpsRestrictionToken);
+ break;
+ case CAMERA:
+ mAppOpsManagerInternal.setGlobalRestriction(OP_CAMERA, enabled,
+ mAppOpsRestrictionToken);
+ break;
+ }
+ }
+
/**
* Remove a sensor use reminder suppression token.
*
@@ -1454,7 +1518,12 @@
@GuardedBy("mListenerLock")
private final SparseArray<SparseArray<RemoteCallbackList<ISensorPrivacyListener>>>
mIndividualSensorListeners = new SparseArray<>();
- private final ArrayMap<ISensorPrivacyListener, DeathRecipient> mDeathRecipients;
+ @GuardedBy("mListenerLock")
+ private final SparseArray<RemoteCallbackList<ISensorPrivacyListener>>
+ mUserGlobalIndividualSensorListeners = new SparseArray<>();
+ @GuardedBy("mListenerLock")
+ private final ArrayMap<ISensorPrivacyListener, Pair<DeathRecipient, Integer>>
+ mDeathRecipients;
private final Context mContext;
SensorPrivacyHandler(Looper looper, Context context) {
@@ -1479,18 +1548,22 @@
mSensorPrivacyServiceImpl));
}
+ public void onUserGlobalSensorPrivacyChanged(int sensor, boolean enabled) {
+ sendMessage(PooledLambda.obtainMessage(
+ SensorPrivacyHandler::handleUserGlobalSensorPrivacyChanged,
+ this, sensor, enabled));
+ }
+
public void addListener(ISensorPrivacyListener listener) {
synchronized (mListenerLock) {
- DeathRecipient deathRecipient = new DeathRecipient(listener);
- mDeathRecipients.put(listener, deathRecipient);
- mListeners.register(listener);
+ if (mListeners.register(listener)) {
+ addDeathRecipient(listener);
+ }
}
}
public void addListener(int userId, int sensor, ISensorPrivacyListener listener) {
synchronized (mListenerLock) {
- DeathRecipient deathRecipient = new DeathRecipient(listener);
- mDeathRecipients.put(listener, deathRecipient);
SparseArray<RemoteCallbackList<ISensorPrivacyListener>> listenersForUser =
mIndividualSensorListeners.get(userId);
if (listenersForUser == null) {
@@ -1502,32 +1575,55 @@
listeners = new RemoteCallbackList<>();
listenersForUser.put(sensor, listeners);
}
- listeners.register(listener);
+ if (listeners.register(listener)) {
+ addDeathRecipient(listener);
+ }
+ }
+ }
+
+ public void addUserGlobalListener(int sensor, ISensorPrivacyListener listener) {
+ synchronized (mListenerLock) {
+ RemoteCallbackList<ISensorPrivacyListener> listeners =
+ mUserGlobalIndividualSensorListeners.get(sensor);
+ if (listeners == null) {
+ listeners = new RemoteCallbackList<>();
+ mUserGlobalIndividualSensorListeners.put(sensor, listeners);
+ }
+ if (listeners.register(listener)) {
+ addDeathRecipient(listener);
+ }
}
}
public void removeListener(ISensorPrivacyListener listener) {
synchronized (mListenerLock) {
- DeathRecipient deathRecipient = mDeathRecipients.remove(listener);
- if (deathRecipient != null) {
- deathRecipient.destroy();
+ if (mListeners.unregister(listener)) {
+ removeDeathRecipient(listener);
}
- mListeners.unregister(listener);
}
}
public void removeListener(int sensor, ISensorPrivacyListener listener) {
synchronized (mListenerLock) {
- DeathRecipient deathRecipient = mDeathRecipients.remove(listener);
- if (deathRecipient != null) {
- deathRecipient.destroy();
- }
-
for (int i = 0, numUsers = mIndividualSensorListeners.size(); i < numUsers; i++) {
RemoteCallbackList callbacks =
mIndividualSensorListeners.valueAt(i).get(sensor);
if (callbacks != null) {
- callbacks.unregister(listener);
+ if (callbacks.unregister(listener)) {
+ removeDeathRecipient(listener);
+ }
+ }
+ }
+ }
+ }
+
+ public void removeUserGlobalListener(int sensor, ISensorPrivacyListener listener) {
+ synchronized (mListenerLock) {
+ RemoteCallbackList callbacks =
+ mUserGlobalIndividualSensorListeners.get(sensor);
+ if (callbacks != null) {
+ if (callbacks.unregister(listener)) {
+ removeDeathRecipient(listener);
}
}
}
@@ -1551,9 +1647,12 @@
SparseArray<RemoteCallbackList<ISensorPrivacyListener>> listenersForUser =
mIndividualSensorListeners.get(userId);
- setGlobalRestriction();
if (userId == mCurrentUser) {
- setGlobalRestriction();
+ mSensorPrivacyServiceImpl.setGlobalRestriction(sensor, enabled);
+ }
+
+ if (userId == mCurrentUser) {
+ onUserGlobalSensorPrivacyChanged(sensor, enabled);
}
if (listenersForUser == null) {
@@ -1563,16 +1662,42 @@
if (listeners == null) {
return;
}
- final int count = listeners.beginBroadcast();
- for (int i = 0; i < count; i++) {
- ISensorPrivacyListener listener = listeners.getBroadcastItem(i);
- try {
- listener.onSensorPrivacyChanged(enabled);
- } catch (RemoteException e) {
- Log.e(TAG, "Caught an exception notifying listener " + listener + ": ", e);
+ try {
+ final int count = listeners.beginBroadcast();
+ for (int i = 0; i < count; i++) {
+ ISensorPrivacyListener listener = listeners.getBroadcastItem(i);
+ try {
+ listener.onSensorPrivacyChanged(enabled);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Caught an exception notifying listener " + listener + ": ", e);
+ }
}
+ } finally {
+ listeners.finishBroadcast();
}
- listeners.finishBroadcast();
+ }
+
+ public void handleUserGlobalSensorPrivacyChanged(int sensor, boolean enabled) {
+ RemoteCallbackList<ISensorPrivacyListener> listeners =
+ mUserGlobalIndividualSensorListeners.get(sensor);
+
+ if (listeners == null) {
+ return;
+ }
+
+ try {
+ final int count = listeners.beginBroadcast();
+ for (int i = 0; i < count; i++) {
+ ISensorPrivacyListener listener = listeners.getBroadcastItem(i);
+ try {
+ listener.onSensorPrivacyChanged(enabled);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Caught an exception notifying listener " + listener + ": ", e);
+ }
+ }
+ } finally {
+ listeners.finishBroadcast();
+ }
}
public void removeSuppressPackageReminderToken(Pair<Integer, UserHandle> key,
@@ -1581,20 +1706,33 @@
SensorPrivacyServiceImpl::removeSuppressPackageReminderToken,
mSensorPrivacyServiceImpl, key, token));
}
- }
- private void setGlobalRestriction() {
- boolean camState =
- mSensorPrivacyServiceImpl
- .isIndividualSensorPrivacyEnabled(mCurrentUser, CAMERA);
- boolean micState =
- mSensorPrivacyServiceImpl
- .isIndividualSensorPrivacyEnabled(mCurrentUser, MICROPHONE);
+ private void addDeathRecipient(ISensorPrivacyListener listener) {
+ Pair<DeathRecipient, Integer> deathRecipient = mDeathRecipients.get(listener);
+ if (deathRecipient == null) {
+ deathRecipient = new Pair<>(new DeathRecipient(listener), 1);
+ } else {
+ int newRefCount = deathRecipient.second + 1;
+ deathRecipient = new Pair<>(deathRecipient.first, newRefCount);
+ }
+ mDeathRecipients.put(listener, deathRecipient);
+ }
- mAppOpsManagerInternal
- .setGlobalRestriction(OP_CAMERA, camState, mAppOpsRestrictionToken);
- mAppOpsManagerInternal
- .setGlobalRestriction(OP_RECORD_AUDIO, micState, mAppOpsRestrictionToken);
+ private void removeDeathRecipient(ISensorPrivacyListener listener) {
+ Pair<DeathRecipient, Integer> deathRecipient = mDeathRecipients.get(listener);
+ if (deathRecipient == null) {
+ return;
+ } else {
+ int newRefCount = deathRecipient.second - 1;
+ if (newRefCount == 0) {
+ mDeathRecipients.remove(listener);
+ deathRecipient.first.destroy();
+ return;
+ }
+ deathRecipient = new Pair<>(deathRecipient.first, newRefCount);
+ }
+ mDeathRecipients.put(listener, deathRecipient);
+ }
}
private final class DeathRecipient implements IBinder.DeathRecipient {
diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java
index abb8243..979a9ee 100644
--- a/services/core/java/com/android/server/am/AppExitInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java
@@ -430,7 +430,13 @@
final ApplicationExitInfo info = new ApplicationExitInfo(raw);
final String[] packages = raw.getPackageList();
- final int uid = raw.getPackageUid();
+ int uid = raw.getRealUid();
+ if (UserHandle.isIsolated(uid)) {
+ Integer k = mIsolatedUidRecords.getUidByIsolatedUid(uid);
+ if (k != null) {
+ uid = k;
+ }
+ }
for (int i = 0; i < packages.length; i++) {
addExitInfoInnerLocked(packages[i], uid, info);
}
@@ -833,14 +839,14 @@
pw.println(prefix + "package: " + packageName);
int size = array.size();
for (int i = 0; i < size; i++) {
- pw.println(prefix + " Historical Process Exit for userId=" + array.keyAt(i));
+ pw.println(prefix + " Historical Process Exit for uid=" + array.keyAt(i));
array.valueAt(i).dumpLocked(pw, prefix + " ", sdf);
}
}
@GuardedBy("mLock")
- private void addExitInfoInnerLocked(String packageName, int userId, ApplicationExitInfo info) {
- AppExitInfoContainer container = mData.get(packageName, userId);
+ private void addExitInfoInnerLocked(String packageName, int uid, ApplicationExitInfo info) {
+ AppExitInfoContainer container = mData.get(packageName, uid);
if (container == null) {
container = new AppExitInfoContainer(mAppExitInfoHistoryListSize);
if (UserHandle.isIsolated(info.getRealUid())) {
@@ -851,7 +857,7 @@
} else {
container.mUid = info.getRealUid();
}
- mData.put(packageName, userId, container);
+ mData.put(packageName, uid, container);
}
container.addExitInfoLocked(info);
}
@@ -997,7 +1003,7 @@
info.setPackageList(app.getPackageList());
info.setReason(ApplicationExitInfo.REASON_UNKNOWN);
info.setStatus(0);
- info.setImportance(procStateToImportance(app.mState.getSetProcState()));
+ info.setImportance(procStateToImportance(app.mState.getReportedProcState()));
info.setPss(app.mProfile.getLastPss());
info.setRss(app.mProfile.getLastRss());
info.setTimestamp(timestamp);
diff --git a/services/core/java/com/android/server/am/LmkdConnection.java b/services/core/java/com/android/server/am/LmkdConnection.java
index 1ecb9eb..598f086 100644
--- a/services/core/java/com/android/server/am/LmkdConnection.java
+++ b/services/core/java/com/android/server/am/LmkdConnection.java
@@ -50,7 +50,7 @@
* Used to hold the data for the statsd atoms logging
* Must be in sync with statslog.h
*/
- private static final int LMKD_REPLY_MAX_SIZE = 214;
+ private static final int LMKD_REPLY_MAX_SIZE = 222;
// connection listener interface
interface LmkdConnectionListener {
diff --git a/services/core/java/com/android/server/am/LmkdStatsReporter.java b/services/core/java/com/android/server/am/LmkdStatsReporter.java
index a8d0582..9158891 100644
--- a/services/core/java/com/android/server/am/LmkdStatsReporter.java
+++ b/services/core/java/com/android/server/am/LmkdStatsReporter.java
@@ -64,11 +64,14 @@
final int freeMemKb = inputData.readInt();
final int freeSwapKb = inputData.readInt();
final int killReason = inputData.readInt();
+ final int thrashing = inputData.readInt();
+ final int maxThrashing = inputData.readInt();
final String procName = inputData.readUTF();
FrameworkStatsLog.write(FrameworkStatsLog.LMK_KILL_OCCURRED, uid, procName, oomScore,
pgFault, pgMajFault, rssInBytes, cacheInBytes, swapInBytes, processStartTimeNS,
- minOomScore, freeMemKb, freeSwapKb, mapKillReason(killReason));
+ minOomScore, freeMemKb, freeSwapKb, mapKillReason(killReason), thrashing,
+ maxThrashing);
} catch (IOException e) {
Slog.e(TAG, "Invalid buffer data. Failed to log LMK_KILL_OCCURRED");
return;
diff --git a/services/core/java/com/android/server/am/PhantomProcessList.java b/services/core/java/com/android/server/am/PhantomProcessList.java
index 4f3438fe..ca31681 100644
--- a/services/core/java/com/android/server/am/PhantomProcessList.java
+++ b/services/core/java/com/android/server/am/PhantomProcessList.java
@@ -305,7 +305,7 @@
}
// Somehow our record doesn't match, remove it anyway
Slog.w(TAG, "Stale " + proc + ", removing");
- mPhantomProcesses.removeAt(index);
+ onPhantomProcessKilledLocked(proc);
} else {
// Is this one of the zombie processes we've known?
final int idx = mZombiePhantomProcesses.indexOfKey(pid);
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index 7520d88..dc6bcd8 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -1086,7 +1086,7 @@
mCurRawAdj = mSetRawAdj = mCurAdj = mSetAdj = mVerifiedAdj = ProcessList.INVALID_ADJ;
mCurCapability = mSetCapability = PROCESS_CAPABILITY_NONE;
mCurSchedGroup = mSetSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
- mCurProcState = mRepProcState = mCurRawProcState = mSetProcState = mAllowStartFgsState =
+ mCurProcState = mCurRawProcState = mSetProcState = mAllowStartFgsState =
PROCESS_STATE_NONEXISTENT;
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 6b7787a..4973d45 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -1103,9 +1103,8 @@
}
public boolean isAdvancedCoexLogicEnabled(Context context) {
- return (Build.IS_USERDEBUG || Build.IS_ENG)
- && Settings.Secure.getInt(context.getContentResolver(),
- CoexCoordinator.SETTING_ENABLE_NAME, 0) != 0;
+ return Settings.Secure.getInt(context.getContentResolver(),
+ CoexCoordinator.SETTING_ENABLE_NAME, 1) != 0;
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 6463e04..013c74d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -70,6 +70,7 @@
private final LockoutTracker mLockoutTracker;
private final boolean mIsRestricted;
private final boolean mAllowBackgroundAuthentication;
+ private final boolean mIsKeyguardBypassEnabled;
protected final long mOperationId;
@@ -97,7 +98,7 @@
int cookie, boolean requireConfirmation, int sensorId, boolean isStrongBiometric,
int statsModality, int statsClient, @Nullable TaskStackListener taskStackListener,
@NonNull LockoutTracker lockoutTracker, boolean allowBackgroundAuthentication,
- boolean shouldVibrate) {
+ boolean shouldVibrate, boolean isKeyguardBypassEnabled) {
super(context, lazyDaemon, token, listener, targetUserId, owner, cookie, sensorId,
shouldVibrate, statsModality, BiometricsProtoEnums.ACTION_AUTHENTICATE,
statsClient);
@@ -110,6 +111,7 @@
mLockoutTracker = lockoutTracker;
mIsRestricted = restricted;
mAllowBackgroundAuthentication = allowBackgroundAuthentication;
+ mIsKeyguardBypassEnabled = isKeyguardBypassEnabled;
}
public @LockoutTracker.LockoutMode int handleFailedAttempt(int userId) {
@@ -394,6 +396,14 @@
return mState;
}
+ /**
+ * @return true if the client supports bypass (e.g. passive auth such as face), and if it's
+ * enabled by the user.
+ */
+ public boolean isKeyguardBypassEnabled() {
+ return mIsKeyguardBypassEnabled;
+ }
+
@Override
public int getProtoEnum() {
return BiometricsProto.CM_AUTHENTICATE;
diff --git a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
index f97cb8a..b576673 100644
--- a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
@@ -26,7 +26,6 @@
import android.os.Looper;
import android.util.Slog;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.biometrics.sensors.BiometricScheduler.SensorType;
import com.android.server.biometrics.sensors.fingerprint.Udfps;
@@ -242,6 +241,11 @@
callback.sendHapticFeedback();
callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
callback.handleLifecycleAfterAuth();
+ } else {
+ // Capacitive fingerprint sensor (or other)
+ callback.sendHapticFeedback();
+ callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
+ callback.handleLifecycleAfterAuth();
}
}
} else {
@@ -268,11 +272,18 @@
AuthenticationClient<?> udfps = mClientMap.getOrDefault(SENSOR_TYPE_UDFPS, null);
AuthenticationClient<?> face = mClientMap.getOrDefault(SENSOR_TYPE_FACE, null);
if (isCurrentFaceAuth(client)) {
- // UDFPS should still be running in this case, do not vibrate. However, we
- // should notify the callback and finish the client, so that Keyguard and
- // BiometricScheduler do not get stuck.
- Slog.d(TAG, "Face rejected in multi-sensor auth, udfps: " + udfps);
- callback.handleLifecycleAfterAuth();
+ if (isUdfpsActivelyAuthing(udfps)) {
+ // UDFPS should still be running in this case, do not vibrate. However, we
+ // should notify the callback and finish the client, so that Keyguard and
+ // BiometricScheduler do not get stuck.
+ Slog.d(TAG, "Face rejected in multi-sensor auth, udfps: " + udfps);
+ callback.handleLifecycleAfterAuth();
+ } else {
+ // UDFPS is not actively authenticating (finger not touching, already
+ // rejected, etc).
+ callback.sendHapticFeedback();
+ callback.handleLifecycleAfterAuth();
+ }
} else if (isCurrentUdfps(client)) {
// Face should either be running, or have already finished
SuccessfulAuth auth = popSuccessfulFaceAuthIfExists(currentTimeMillis);
diff --git a/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java b/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java
index c8867ea..b4c82f2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java
@@ -48,6 +48,64 @@
private boolean mLightSensorEnabled = false;
private boolean mShouldLogMetrics = true;
+ /**
+ * Probe for loggable attributes that can be continuously monitored, such as ambient light.
+ *
+ * Disable probes when the sensors are in states that are not interesting for monitoring
+ * purposes to save power.
+ */
+ protected interface Probe {
+ /** Ensure the probe is actively sampling for new data. */
+ void enable();
+ /** Stop sampling data. */
+ void disable();
+ }
+
+ /**
+ * Client monitor callback that exposes a probe.
+ *
+ * Disables the probe when the operation completes.
+ */
+ protected static class CallbackWithProbe<T extends Probe>
+ implements BaseClientMonitor.Callback {
+ private final boolean mStartWithClient;
+ private final T mProbe;
+
+ public CallbackWithProbe(@NonNull T probe, boolean startWithClient) {
+ mProbe = probe;
+ mStartWithClient = startWithClient;
+ }
+
+ @Override
+ public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
+ if (mStartWithClient) {
+ mProbe.enable();
+ }
+ }
+
+ @Override
+ public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {
+ mProbe.disable();
+ }
+
+ @NonNull
+ public T getProbe() {
+ return mProbe;
+ }
+ }
+
+ private class ALSProbe implements Probe {
+ @Override
+ public void enable() {
+ setLightSensorLoggingEnabled(getAmbientLightSensor(mSensorManager));
+ }
+
+ @Override
+ public void disable() {
+ setLightSensorLoggingEnabled(null);
+ }
+ }
+
// report only the most recent value
// consider com.android.server.display.utils.AmbientFilter or similar if need arises
private volatile float mLastAmbientLux = 0;
@@ -285,21 +343,17 @@
return latency;
}
- /** Get a callback to start/stop ALS capture when client runs. */
+ /**
+ * Get a callback to start/stop ALS capture when client runs.
+ *
+ * If the probe should not run for the entire operation, do not set startWithClient and
+ * start/stop the problem when needed.
+ *
+ * @param startWithClient if probe should start automatically when the operation starts.
+ */
@NonNull
- protected BaseClientMonitor.Callback createALSCallback() {
- return new BaseClientMonitor.Callback() {
- @Override
- public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
- setLightSensorLoggingEnabled(getAmbientLightSensor(mSensorManager));
- }
-
- @Override
- public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
- boolean success) {
- setLightSensorLoggingEnabled(null);
- }
- };
+ protected CallbackWithProbe<Probe> createALSCallback(boolean startWithClient) {
+ return new CallbackWithProbe<>(new ALSProbe(), startWithClient);
}
/** The sensor to use for ALS logging. */
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 219e063..12d6b08 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -251,7 +251,8 @@
@Override // Binder call
public void authenticate(final IBinder token, final long operationId, int userId,
- final IFaceServiceReceiver receiver, final String opPackageName) {
+ final IFaceServiceReceiver receiver, final String opPackageName,
+ boolean isKeyguardBypassEnabled) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
// TODO(b/152413782): If the sensor supports face detect and the device is encrypted or
@@ -275,7 +276,7 @@
provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
0 /* cookie */,
new ClientMonitorCallbackConverter(receiver), opPackageName, restricted,
- statsClient, isKeyguard);
+ statsClient, isKeyguard, isKeyguardBypassEnabled);
}
@Override // Binder call
@@ -318,10 +319,12 @@
return;
}
+ final boolean isKeyguardBypassEnabled = false; // only valid for keyguard clients
final boolean restricted = true; // BiometricPrompt is always restricted
provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie,
new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted,
- BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, allowBackgroundAuthentication);
+ BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, allowBackgroundAuthentication,
+ isKeyguardBypassEnabled);
}
@Override // Binder call
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
index 1d2ac3b..93ab1b6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
@@ -110,7 +110,7 @@
void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient,
- boolean allowBackgroundAuthentication);
+ boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled);
void cancelAuthentication(int sensorId, @NonNull IBinder token);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
index 35c1745..f7fd8d0 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -69,11 +69,13 @@
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId,
boolean isStrongBiometric, int statsClient, @NonNull UsageStats usageStats,
- @NonNull LockoutCache lockoutCache, boolean allowBackgroundAuthentication) {
+ @NonNull LockoutCache lockoutCache, boolean allowBackgroundAuthentication,
+ boolean isKeyguardBypassEnabled) {
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */,
- lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */);
+ lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */,
+ isKeyguardBypassEnabled);
mUsageStats = usageStats;
mLockoutCache = lockoutCache;
mNotificationManager = context.getSystemService(NotificationManager.class);
@@ -98,7 +100,7 @@
@NonNull
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
- return new CompositeCallback(createALSCallback(), callback);
+ return new CompositeCallback(createALSCallback(true /* startWithClient */), callback);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
index 55c987a..a806277 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
@@ -109,7 +109,8 @@
@NonNull
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
- return new CompositeCallback(mPreviewHandleDeleterCallback, createALSCallback(), callback);
+ return new CompositeCallback(mPreviewHandleDeleterCallback,
+ createALSCallback(true /* startWithClient */), callback);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index 5c24108..718b9da 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -378,7 +378,7 @@
public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient,
- boolean allowBackgroundAuthentication) {
+ boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
mHandler.post(() -> {
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
final FaceAuthenticationClient client = new FaceAuthenticationClient(
@@ -386,7 +386,7 @@
operationId, restricted, opPackageName, cookie,
false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
mUsageStats, mSensors.get(sensorId).getLockoutCache(),
- allowBackgroundAuthentication);
+ allowBackgroundAuthentication, isKeyguardBypassEnabled);
scheduleForSensor(sensorId, client);
});
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index da4ad86..d05333d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -622,7 +622,7 @@
public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter receiver,
@NonNull String opPackageName, boolean restricted, int statsClient,
- boolean allowBackgroundAuthentication) {
+ boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
@@ -630,7 +630,8 @@
final FaceAuthenticationClient client = new FaceAuthenticationClient(mContext,
mLazyDaemon, token, receiver, userId, operationId, restricted, opPackageName,
cookie, false /* requireConfirmation */, mSensorId, isStrongBiometric,
- statsClient, mLockoutTracker, mUsageStats, allowBackgroundAuthentication);
+ statsClient, mLockoutTracker, mUsageStats, allowBackgroundAuthentication,
+ isKeyguardBypassEnabled);
mScheduler.scheduleClientMonitor(client);
});
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
index e65245b..c33b957 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
@@ -61,11 +61,13 @@
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId,
boolean isStrongBiometric, int statsClient, @NonNull LockoutTracker lockoutTracker,
- @NonNull UsageStats usageStats, boolean allowBackgroundAuthentication) {
+ @NonNull UsageStats usageStats, boolean allowBackgroundAuthentication,
+ boolean isKeyguardBypassEnabled) {
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */,
- lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */);
+ lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */,
+ isKeyguardBypassEnabled);
mUsageStats = usageStats;
final Resources resources = getContext().getResources();
@@ -88,7 +90,7 @@
@NonNull
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
- return new CompositeCallback(createALSCallback(), callback);
+ return new CompositeCallback(createALSCallback(true /* startWithClient */), callback);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
index 455d6f8..80828cced 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
@@ -69,7 +69,7 @@
@NonNull
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
- return new CompositeCallback(createALSCallback(), callback);
+ return new CompositeCallback(createALSCallback(true /* startWithClient */), callback);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 14d1822..99e6e62 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -55,6 +55,7 @@
@NonNull private final LockoutCache mLockoutCache;
@Nullable private final IUdfpsOverlayController mUdfpsOverlayController;
@NonNull private final FingerprintSensorPropertiesInternal mSensorProps;
+ @NonNull private final CallbackWithProbe<Probe> mALSProbeCallback;
@Nullable private ICancellationSignal mCancellationSignal;
private boolean mIsPointerDown;
@@ -71,10 +72,12 @@
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted, owner,
cookie, requireConfirmation, sensorId, isStrongBiometric,
BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener,
- lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */);
+ lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */,
+ false /* isKeyguardBypassEnabled */);
mLockoutCache = lockoutCache;
mUdfpsOverlayController = udfpsOverlayController;
mSensorProps = sensorProps;
+ mALSProbeCallback = createALSCallback(false /* startWithClient */);
}
@Override
@@ -92,7 +95,7 @@
@NonNull
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
- return new CompositeCallback(createALSCallback(), callback);
+ return new CompositeCallback(mALSProbeCallback, callback);
}
@Override
@@ -170,7 +173,9 @@
try {
mIsPointerDown = true;
mState = STATE_STARTED;
+ mALSProbeCallback.getProbe().enable();
getFreshDaemon().onPointerDown(0 /* pointerId */, x, y, minor, major);
+
if (getListener() != null) {
getListener().onUdfpsPointerDown(getSensorId());
}
@@ -184,7 +189,9 @@
try {
mIsPointerDown = false;
mState = STATE_STARTED_PAUSED;
+ mALSProbeCallback.getProbe().disable();
getFreshDaemon().onPointerUp(0 /* pointerId */);
+
if (getListener() != null) {
getListener().onUdfpsPointerUp(getSensorId());
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index e8200af..c420c5c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -84,7 +84,7 @@
@NonNull
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
- return new CompositeCallback(createALSCallback(), callback);
+ return new CompositeCallback(createALSCallback(true /* startWithClient */), callback);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
index 9347244..7558d15 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
@@ -54,6 +54,7 @@
private final LockoutFrameworkImpl mLockoutFrameworkImpl;
@Nullable private final IUdfpsOverlayController mUdfpsOverlayController;
@NonNull private final FingerprintSensorPropertiesInternal mSensorProps;
+ @NonNull private final CallbackWithProbe<Probe> mALSProbeCallback;
private boolean mIsPointerDown;
@@ -70,10 +71,12 @@
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener,
- lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */);
+ lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */,
+ false /* isKeyguardBypassEnabled */);
mLockoutFrameworkImpl = lockoutTracker;
mUdfpsOverlayController = udfpsOverlayController;
mSensorProps = sensorProps;
+ mALSProbeCallback = createALSCallback(false /* startWithClient */);
}
@Override
@@ -91,7 +94,7 @@
@NonNull
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
- return new CompositeCallback(createALSCallback(), callback);
+ return new CompositeCallback(mALSProbeCallback, callback);
}
@Override
@@ -188,7 +191,9 @@
public void onPointerDown(int x, int y, float minor, float major) {
mIsPointerDown = true;
mState = STATE_STARTED;
+ mALSProbeCallback.getProbe().enable();
UdfpsHelper.onFingerDown(getFreshDaemon(), x, y, minor, major);
+
if (getListener() != null) {
try {
getListener().onUdfpsPointerDown(getSensorId());
@@ -202,7 +207,9 @@
public void onPointerUp() {
mIsPointerDown = false;
mState = STATE_STARTED_PAUSED;
+ mALSProbeCallback.getProbe().disable();
UdfpsHelper.onFingerUp(getFreshDaemon());
+
if (getListener() != null) {
try {
getListener().onUdfpsPointerUp(getSensorId());
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
index 250e132..dc70534 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
@@ -77,7 +77,7 @@
@NonNull
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
- return new CompositeCallback(createALSCallback(), callback);
+ return new CompositeCallback(createALSCallback(true /* startWithClient */), callback);
}
@Override
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 1edede5..59f536c 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -778,7 +778,7 @@
setUpAutoBrightness(mContext.getResources(), mHandler);
reloadReduceBrightColours();
mHbmController.resetHbmData(info.width, info.height, token,
- mDisplayDeviceConfig.getHighBrightnessModeData(), mBrightnessSetting);
+ mDisplayDeviceConfig.getHighBrightnessModeData());
}
private void sendUpdatePowerState() {
@@ -968,7 +968,6 @@
final boolean mustNotify;
final int previousPolicy;
boolean mustInitialize = false;
- boolean shouldSaveBrightnessInfo = true;
int brightnessAdjustmentFlags = 0;
mBrightnessReasonTemp.set(null);
synchronized (mLock) {
@@ -1099,7 +1098,6 @@
if (state == Display.STATE_OFF) {
brightnessState = PowerManager.BRIGHTNESS_OFF_FLOAT;
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_SCREEN_OFF);
- shouldSaveBrightnessInfo = false;
}
// Always use the VR brightness when in the VR state.
@@ -1217,6 +1215,10 @@
brightnessAdjustmentFlags = 0;
}
} else {
+ // Any non-auto-brightness values such as override or temporary should still be subject
+ // to clamping so that they don't go beyond the current max as specified by HBM
+ // Controller.
+ brightnessState = clampScreenBrightness(brightnessState);
mAppliedAutoBrightness = false;
brightnessAdjustmentFlags = 0;
}
@@ -1224,9 +1226,8 @@
// Use default brightness when dozing unless overridden.
if ((Float.isNaN(brightnessState))
&& Display.isDozeState(state)) {
- brightnessState = mScreenBrightnessDozeConfig;
+ brightnessState = clampScreenBrightness(mScreenBrightnessDozeConfig);
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_DEFAULT);
- shouldSaveBrightnessInfo = false;
}
// Apply manual brightness.
@@ -1241,12 +1242,13 @@
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_MANUAL);
}
- // Save out the brightness info now that the brightness state for this iteration has been
- // finalized and before we send out notifications about the brightness changing.
- if (shouldSaveBrightnessInfo) {
- saveBrightnessInfo(brightnessState);
-
- }
+ // The current brightness to use has been calculated at this point (minus the adjustments
+ // like low-power and dim), and HbmController should be notified so that it can accurately
+ // calculate HDR or HBM levels. We specifically do it here instead of having HbmController
+ // listen to the brightness setting because certain brightness sources (just as an app
+ // override) are not saved to the setting, but should be reflected in HBM
+ // calculations.
+ mHbmController.onBrightnessChanged(brightnessState);
if (updateScreenBrightnessSetting) {
// Tell the rest of the system about the new brightness in case we had to change it
@@ -1257,6 +1259,10 @@
putScreenBrightnessSetting(brightnessState, /* updateCurrent */ true);
}
+ // We save the brightness info *after* the brightness setting has been changed so that
+ // the brightness info reflects the latest value.
+ saveBrightnessInfo(getScreenBrightnessSetting());
+
// Apply dimming by at least some minimum amount when user activity
// timeout is about to expire.
if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
@@ -1533,7 +1539,7 @@
mHandler.post(mOnBrightnessChangeRunnable);
// TODO(b/192258832): Switch the HBMChangeCallback to a listener pattern.
mAutomaticBrightnessController.update();
- }, mContext, mBrightnessSetting);
+ }, mContext);
}
private void blockScreenOn() {
@@ -2336,7 +2342,7 @@
try {
// TODO(brightnessfloat): change BatteryStats to use float
mBatteryStats.noteScreenBrightness(BrightnessSynchronizer.brightnessFloatToInt(
- brightness));
+ brightness, null));
} catch (RemoteException e) {
// same process
}
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java
index 645131c..2791f6a 100644
--- a/services/core/java/com/android/server/display/HighBrightnessModeController.java
+++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java
@@ -37,7 +37,6 @@
import android.view.SurfaceControlHdrLayerInfoListener;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.display.BrightnessSetting.BrightnessSettingListener;
import com.android.server.display.DisplayDeviceConfig.HighBrightnessModeData;
import com.android.server.display.DisplayManagerService.Clock;
@@ -70,7 +69,6 @@
private final Context mContext;
private final SettingsObserver mSettingsObserver;
private final Injector mInjector;
- private final BrightnessSettingListener mBrightnessSettingListener = this::onBrightnessChanged;
private HdrListener mHdrListener;
private HighBrightnessModeData mHbmData;
@@ -86,7 +84,6 @@
private boolean mIsBlockedByLowPowerMode = false;
private int mWidth;
private int mHeight;
- private BrightnessSetting mBrightnessSetting;
private float mAmbientLux;
/**
@@ -103,30 +100,30 @@
HighBrightnessModeController(Handler handler, int width, int height, IBinder displayToken,
float brightnessMin, float brightnessMax, HighBrightnessModeData hbmData,
- Runnable hbmChangeCallback, Context context, BrightnessSetting brightnessSetting) {
+ Runnable hbmChangeCallback, Context context) {
this(new Injector(), handler, width, height, displayToken, brightnessMin, brightnessMax,
- hbmData, hbmChangeCallback, context, brightnessSetting);
+ hbmData, hbmChangeCallback, context);
}
@VisibleForTesting
HighBrightnessModeController(Injector injector, Handler handler, int width, int height,
IBinder displayToken, float brightnessMin, float brightnessMax,
HighBrightnessModeData hbmData, Runnable hbmChangeCallback,
- Context context, BrightnessSetting brightnessSetting) {
+ Context context) {
mInjector = injector;
mContext = context;
mClock = injector.getClock();
mHandler = handler;
+ mBrightness = brightnessMin;
mBrightnessMin = brightnessMin;
mBrightnessMax = brightnessMax;
- mBrightness = brightnessSetting.getBrightness();
mHbmChangeCallback = hbmChangeCallback;
mSkinThermalStatusObserver = new SkinThermalStatusObserver(mInjector, mHandler);
mSettingsObserver = new SettingsObserver(mHandler);
mRecalcRunnable = this::recalculateTimeAllowance;
mHdrListener = new HdrListener();
- resetHbmData(width, height, displayToken, hbmData, brightnessSetting);
+ resetHbmData(width, height, displayToken, hbmData);
}
void setAutoBrightnessEnabled(boolean isEnabled) {
@@ -185,7 +182,6 @@
}
}
- @VisibleForTesting
void onBrightnessChanged(float brightness) {
if (!deviceSupportsHbm()) {
return;
@@ -224,12 +220,11 @@
mSettingsObserver.stopObserving();
}
- void resetHbmData(int width, int height, IBinder displayToken, HighBrightnessModeData hbmData,
- BrightnessSetting brightnessSetting) {
+ void resetHbmData(int width, int height, IBinder displayToken, HighBrightnessModeData hbmData) {
mWidth = width;
mHeight = height;
mHbmData = hbmData;
- resetBrightnessSetting(brightnessSetting);
+
unregisterHdrListener();
mSkinThermalStatusObserver.stopObserving();
mSettingsObserver.stopObserving();
@@ -261,9 +256,12 @@
pw.println(" mBrightness=" + mBrightness);
pw.println(" mCurrentMin=" + getCurrentBrightnessMin());
pw.println(" mCurrentMax=" + getCurrentBrightnessMax());
- pw.println(" mHbmMode=" + BrightnessInfo.hbmToString(mHbmMode));
+ pw.println(" mHbmMode=" + BrightnessInfo.hbmToString(mHbmMode)
+ + (mHbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR
+ ? "(" + getHdrBrightnessValue() + ")" : ""));
pw.println(" mHbmData=" + mHbmData);
- pw.println(" mAmbientLux=" + mAmbientLux);
+ pw.println(" mAmbientLux=" + mAmbientLux
+ + (mIsAutoBrightnessEnabled ? "" : " (old/invalid)"));
pw.println(" mIsInAllowedAmbientRange=" + mIsInAllowedAmbientRange);
pw.println(" mIsAutoBrightnessEnabled=" + mIsAutoBrightnessEnabled);
pw.println(" mIsHdrLayerPresent=" + mIsHdrLayerPresent);
@@ -301,16 +299,6 @@
return event.startTimeMillis;
}
- private void resetBrightnessSetting(BrightnessSetting brightnessSetting) {
- if (mBrightnessSetting != null) {
- mBrightnessSetting.unregisterListener(mBrightnessSettingListener);
- }
- mBrightnessSetting = brightnessSetting;
- if (mBrightnessSetting != null) {
- mBrightnessSetting.registerListener(mBrightnessSettingListener);
- }
- }
-
private boolean isCurrentlyAllowed() {
// Returns true if HBM is allowed (above the ambient lux threshold) and there's still
// time within the current window for additional HBM usage. We return false if there is an
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index f953cc8..ff143bf 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -601,12 +601,6 @@
&& SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) {
mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND;
}
- if (res.getBoolean(
- com.android.internal.R.bool.config_maskMainBuiltInDisplayCutout)) {
- mInfo.flags |= DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT;
- }
- mInfo.displayCutout = DisplayCutout.fromResourcesRectApproximation(res,
- mInfo.width, mInfo.height);
mInfo.roundedCorners = RoundedCorners.fromResources(
res, mInfo.width, mInfo.height);
} else {
@@ -620,6 +614,12 @@
}
}
+ if (DisplayCutout.getMaskBuiltInDisplayCutout(res, mInfo.uniqueId)) {
+ mInfo.flags |= DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT;
+ }
+ mInfo.displayCutout = DisplayCutout.fromResourcesRectApproximation(res,
+ mInfo.uniqueId, mInfo.width, mInfo.height);
+
if (mStaticDisplayInfo.isInternal) {
mInfo.type = Display.TYPE_INTERNAL;
mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
@@ -795,11 +795,12 @@
mBacklightAdapter.setBacklight(sdrBacklight, sdrNits, backlight, nits);
Trace.traceCounter(Trace.TRACE_TAG_POWER,
"ScreenBrightness",
- BrightnessSynchronizer.brightnessFloatToInt(brightnessState));
+ BrightnessSynchronizer.brightnessFloatToInt(
+ brightnessState, null));
Trace.traceCounter(Trace.TRACE_TAG_POWER,
"SdrScreenBrightness",
BrightnessSynchronizer.brightnessFloatToInt(
- sdrBrightnessState));
+ sdrBrightnessState, null));
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index 91f14de..bebe6ed 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -293,7 +293,7 @@
+ ": brightness=" + brightness);
return;
}
- int brightnessInt = BrightnessSynchronizer.brightnessFloatToInt(brightness);
+ int brightnessInt = BrightnessSynchronizer.brightnessFloatToInt(brightness, null);
int color = brightnessInt & 0x000000ff;
color = 0xff000000 | (color << 16) | (color << 8) | color;
setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 00ef97d..5429484 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2252,12 +2252,29 @@
(params.installFlags & PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK)
== 0;
synchronized (mLock) {
- if (checkApexUpdateAllowed && !isApexUpdateAllowed(mPackageName)) {
+ if (checkApexUpdateAllowed && !isApexUpdateAllowed(mPackageName,
+ mInstallSource.installerPackageName)) {
onSessionValidationFailure(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
- "Update of APEX package " + mPackageName + " is not allowed");
+ "Update of APEX package " + mPackageName + " is not allowed for "
+ + mInstallSource.installerPackageName);
return;
}
}
+
+ if (!params.isStaged) {
+ // For non-staged APEX installs also check if there is a staged session that
+ // contains the same APEX. If that's the case, we should fail this session.
+ synchronized (mLock) {
+ int sessionId = mStagingManager.getSessionIdByPackageName(mPackageName);
+ if (sessionId != -1) {
+ onSessionValidationFailure(
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
+ "Staged session " + sessionId + " already contains "
+ + mPackageName);
+ return;
+ }
+ }
+ }
}
if (params.isStaged) {
@@ -2798,9 +2815,23 @@
return sessionContains((s) -> !s.isApexSession());
}
- private boolean isApexUpdateAllowed(String apexPackageName) {
- return mPm.getModuleInfo(apexPackageName, 0) != null
- || SystemConfig.getInstance().getAllowedVendorApexes().contains(apexPackageName);
+ private boolean isApexUpdateAllowed(String apexPackageName, String installerPackageName) {
+ if (mPm.getModuleInfo(apexPackageName, 0) != null) {
+ final String modulesInstaller =
+ SystemConfig.getInstance().getModulesInstallerPackageName();
+ if (modulesInstaller == null) {
+ Slog.w(TAG, "No modules installer defined");
+ return false;
+ }
+ return modulesInstaller.equals(installerPackageName);
+ }
+ final String vendorApexInstaller =
+ SystemConfig.getInstance().getAllowedVendorApexes().get(apexPackageName);
+ if (vendorApexInstaller == null) {
+ Slog.w(TAG, apexPackageName + " is not allowed to be updated");
+ return false;
+ }
+ return vendorApexInstaller.equals(installerPackageName);
}
/**
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 4ac5be2..bdbcb27 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -777,6 +777,26 @@
}
}
+ /**
+ * Returns id of a committed and non-finalized stated session that contains same
+ * {@code packageName}, or {@code -1} if no sessions have this {@code packageName} staged.
+ */
+ int getSessionIdByPackageName(@NonNull String packageName) {
+ synchronized (mStagedSessions) {
+ for (int i = 0; i < mStagedSessions.size(); i++) {
+ StagedSession stagedSession = mStagedSessions.valueAt(i);
+ if (!stagedSession.isCommitted() || stagedSession.isDestroyed()
+ || stagedSession.isInTerminalState()) {
+ continue;
+ }
+ if (stagedSession.getPackageName().equals(packageName)) {
+ return stagedSession.sessionId();
+ }
+ }
+ }
+ return -1;
+ }
+
@VisibleForTesting
void createSession(@NonNull StagedSession sessionInfo) {
synchronized (mStagedSessions) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index fb4d96e..d1df989 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3020,7 +3020,8 @@
@Override
public void onKeyguardOccludedChangedLw(boolean occluded) {
- if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
+ if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()
+ && !WindowManagerService.sEnableShellTransitions) {
mPendingKeyguardOccluded = occluded;
mKeyguardOccludedChanged = true;
} else {
@@ -4246,6 +4247,7 @@
pmWakeReason)) + ")");
}
+ mActivityTaskManagerInternal.notifyWakingUp();
mDefaultDisplayPolicy.setAwake(true);
// Since goToSleep performs these functions synchronously, we must
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index d95e826..cdab91b 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -22,8 +22,8 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
-import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
+import android.view.InsetsVisibilities;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
@@ -133,7 +133,7 @@
/** @see com.android.internal.statusbar.IStatusBar#onSystemBarAttributesChanged */
void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, InsetsState requestedState, String packageName);
+ @Behavior int behavior, InsetsVisibilities requestedVisibilities, String packageName);
/** @see com.android.internal.statusbar.IStatusBar#showTransient */
void showTransient(int displayId, @InternalInsetsType int[] types);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 47fdc4e..ff7e903 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -59,8 +59,8 @@
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
-import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
+import android.view.InsetsVisibilities;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
@@ -527,13 +527,14 @@
@Override
public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, InsetsState requestedState, String packageName) {
+ @Behavior int behavior, InsetsVisibilities requestedVisibilities,
+ String packageName) {
getUiState(displayId).setBarAttributes(appearance, appearanceRegions,
- navbarColorManagedByIme, behavior, requestedState, packageName);
+ navbarColorManagedByIme, behavior, requestedVisibilities, packageName);
if (mBar != null) {
try {
mBar.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions,
- navbarColorManagedByIme, behavior, requestedState, packageName);
+ navbarColorManagedByIme, behavior, requestedVisibilities, packageName);
} catch (RemoteException ex) { }
}
}
@@ -1110,7 +1111,7 @@
private final ArraySet<Integer> mTransientBarTypes = new ArraySet<>();
private boolean mNavbarColorManagedByIme = false;
private @Behavior int mBehavior;
- private InsetsState mRequestedState = new InsetsState();
+ private InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
private String mPackageName = "none";
private int mDisabled1 = 0;
private int mDisabled2 = 0;
@@ -1121,12 +1122,13 @@
private void setBarAttributes(@Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, InsetsState requestedState, String packageName) {
+ @Behavior int behavior, InsetsVisibilities requestedVisibilities,
+ String packageName) {
mAppearance = appearance;
mAppearanceRegions = appearanceRegions;
mNavbarColorManagedByIme = navbarColorManagedByIme;
mBehavior = behavior;
- mRequestedState = requestedState;
+ mRequestedVisibilities = requestedVisibilities;
mPackageName = packageName;
}
@@ -1247,7 +1249,7 @@
state.mAppearance, state.mAppearanceRegions, state.mImeWindowVis,
state.mImeBackDisposition, state.mShowImeSwitcher,
gatherDisableActionsLocked(mCurrentUserId, 2), state.mImeToken,
- state.mNavbarColorManagedByIme, state.mBehavior, state.mRequestedState,
+ state.mNavbarColorManagedByIme, state.mBehavior, state.mRequestedVisibilities,
state.mPackageName, transientBarTypes);
}
}
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 3c0a05b..450257f 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -195,6 +195,7 @@
@VisibleForTesting(visibility = Visibility.PRIVATE)
static final int SAFEMODE_TIMEOUT_SECONDS = 30;
+ private static final int SAFEMODE_TIMEOUT_SECONDS_TEST_MODE = 10;
private interface EventInfo {}
@@ -1082,7 +1083,9 @@
createScheduledAlarm(
SAFEMODE_TIMEOUT_ALARM,
delayedMessage,
- TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS));
+ mVcnContext.isInTestMode()
+ ? TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS_TEST_MODE)
+ : TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS));
}
private void cancelSafeModeAlarm() {
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 1f5ff25..331b8de 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -1183,7 +1183,7 @@
try {
final Intent baseActivityIntent;
final boolean launchedFromHome;
-
+ final boolean isLastRunningActivity;
synchronized (mGlobalLock) {
final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
if (r == null) return;
@@ -1195,7 +1195,9 @@
return;
}
- final Intent baseIntent = r.getTask().getBaseIntent();
+ final Task task = r.getTask();
+ isLastRunningActivity = task.topRunningActivity() == r;
+ final Intent baseIntent = task.getBaseIntent();
final boolean activityIsBaseActivity = baseIntent != null
&& r.mActivityComponent.equals(baseIntent.getComponent());
baseActivityIntent = activityIsBaseActivity ? r.intent : null;
@@ -1205,12 +1207,13 @@
// If the activity is one of the main entry points for the application, then we should
// refrain from finishing the activity and instead move it to the back to keep it in
// memory. The requirements for this are:
- // 1. The current activity is the base activity for the task.
- // 2. a. If the activity was launched by the home process, we trust that its intent
+ // 1. The activity is the last running activity in the task.
+ // 2. The current activity is the base activity for the task.
+ // 3. a. If the activity was launched by the home process, we trust that its intent
// was resolved, so we check if the it is a main intent for the application.
// b. Otherwise, we query Package Manager to verify whether the activity is a
// launcher activity for the application.
- if (baseActivityIntent != null
+ if (baseActivityIntent != null && isLastRunningActivity
&& ((launchedFromHome && ActivityRecord.isMainIntent(baseActivityIntent))
|| isLauncherActivity(baseActivityIntent.getComponent()))) {
moveActivityTaskToBack(token, false /* nonRoot */);
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index b1163c4..005a62a 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -936,9 +936,11 @@
// This will avoid any races with other operations that modify the ActivityRecord.
final TransitionInfoSnapshot infoSnapshot = new TransitionInfoSnapshot(info);
if (info.isInterestingToLoggerAndObserver()) {
+ final long timestamp = info.mTransitionStartTimeNs;
+ final long uptime = info.mTransitionDeviceUptimeMs;
+ final int transitionDelay = info.mCurrentTransitionDelayMs;
mLoggerHandler.post(() -> logAppTransition(
- info.mTransitionDeviceUptimeMs, info.mCurrentTransitionDelayMs,
- infoSnapshot, isHibernating));
+ timestamp, uptime, transitionDelay, infoSnapshot, isHibernating));
}
mLoggerHandler.post(() -> logAppDisplayed(infoSnapshot));
if (info.mPendingFullyDrawn != null) {
@@ -949,8 +951,8 @@
}
// This gets called on another thread without holding the activity manager lock.
- private void logAppTransition(long transitionDeviceUptimeMs, int currentTransitionDelayMs,
- TransitionInfoSnapshot info, boolean isHibernating) {
+ private void logAppTransition(long transitionStartTimeNs, long transitionDeviceUptimeMs,
+ int currentTransitionDelayMs, TransitionInfoSnapshot info, boolean isHibernating) {
final LogMaker builder = new LogMaker(APP_TRANSITION);
builder.setPackageName(info.packageName);
builder.setType(info.type);
@@ -1001,7 +1003,7 @@
info.launchedActivityName,
info.launchedActivityLaunchedFromPackage,
isInstantApp,
- transitionDeviceUptimeMs,
+ 0 /* deprecated transitionDeviceUptimeMs */,
info.reason,
currentTransitionDelayMs,
info.startingWindowDelayMs,
@@ -1015,7 +1017,8 @@
isHibernating,
isIncremental,
isLoading,
- info.launchedActivityName.hashCode());
+ info.launchedActivityName.hashCode(),
+ TimeUnit.NANOSECONDS.toMillis(transitionStartTimeNs));
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 088bbae..5970f62 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -3446,6 +3446,10 @@
return;
}
finishing = true;
+ final TaskFragment taskFragment = getTaskFragment();
+ if (taskFragment != null) {
+ taskFragment.sendTaskFragmentInfoChanged();
+ }
if (stopped) {
abortAndClearOptionsAnimation();
}
@@ -5150,6 +5154,12 @@
void notifyAppStopped() {
ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppStopped: %s", this);
mAppStopped = true;
+ // This is to fix the edge case that auto-enter-pip is finished in Launcher but app calls
+ // setAutoEnterEnabled(false) and transitions to STOPPED state, see b/191930787.
+ // Clear any surface transactions and content overlay in this case.
+ if (task != null && task.mLastRecentsAnimationTransaction != null) {
+ task.clearLastRecentsAnimationTransaction(true /* forceRemoveOverlay */);
+ }
// Reset the last saved PiP snap fraction on app stop.
mDisplayContent.mPinnedTaskController.onActivityHidden(mActivityComponent);
mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(this);
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index d08d285..b71ad2e 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -490,11 +490,22 @@
return START_SUCCESS;
}
- void startActivityInTaskFragment(@NonNull TaskFragment taskFragment,
- @NonNull Intent activityIntent, @Nullable Bundle activityOptions) {
- obtainStarter(activityIntent, "startActivityInTaskFragment")
+ /**
+ * Starts an activity in the TaskFragment.
+ * @param taskFragment TaskFragment {@link TaskFragment} to start the activity in.
+ * @param activityIntent intent to start the activity.
+ * @param activityOptions ActivityOptions to start the activity with.
+ * @param resultTo the caller activity
+ * @return the start result.
+ */
+ int startActivityInTaskFragment(@NonNull TaskFragment taskFragment,
+ @NonNull Intent activityIntent, @Nullable Bundle activityOptions,
+ @Nullable IBinder resultTo) {
+ return obtainStarter(activityIntent, "startActivityInTaskFragment")
.setActivityOptions(activityOptions)
.setInTaskFragment(taskFragment)
+ .setResultTo(resultTo)
+ .setRequestCode(-1)
.setCallingUid(Binder.getCallingUid())
.setCallingPid(Binder.getCallingPid())
.execute();
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index c881359..4e73bf3 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -24,6 +24,7 @@
import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
import static android.app.ActivityManager.START_FLAG_ONLY_IF_NEEDED;
+import static android.app.ActivityManager.START_PERMISSION_DENIED;
import static android.app.ActivityManager.START_RETURN_INTENT_TO_CALLER;
import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
import static android.app.ActivityManager.START_SUCCESS;
@@ -744,7 +745,7 @@
Slog.w(TAG, "Unable to find app for caller " + mRequest.caller + " (pid="
+ mRequest.callingPid + ") when starting: " + mRequest.intent.toString());
SafeActivityOptions.abort(mRequest.activityOptions);
- return ActivityManager.START_PERMISSION_DENIED;
+ return START_PERMISSION_DENIED;
}
}
@@ -858,7 +859,7 @@
} else {
Slog.w(TAG, "Unable to find app for caller " + caller + " (pid=" + callingPid
+ ") when starting: " + intent.toString());
- err = ActivityManager.START_PERMISSION_DENIED;
+ err = START_PERMISSION_DENIED;
}
}
@@ -1952,10 +1953,41 @@
}
}
+ if (mInTaskFragment != null && mInTaskFragment.getTask() != null) {
+ final int hostUid = mInTaskFragment.getTask().effectiveUid;
+ final int embeddingUid = targetTask != null ? targetTask.effectiveUid : r.getUid();
+ if (!canTaskBeEmbedded(hostUid, embeddingUid)) {
+ Slog.e(TAG, "Cannot embed activity to a task owned by " + hostUid + " targetTask= "
+ + targetTask);
+ return START_PERMISSION_DENIED;
+ }
+ }
+
return START_SUCCESS;
}
/**
+ * Return {@code true} if the {@param task} can embed another task.
+ * @param hostUid the uid of the host task
+ * @param embeddedUid the uid of the task the are going to be embedded
+ */
+ private boolean canTaskBeEmbedded(int hostUid, int embeddedUid) {
+ // Allowing the embedding if the task is owned by system.
+ if (hostUid == Process.SYSTEM_UID) {
+ return true;
+ }
+
+ // Allowing embedding if the host task is owned by an app that has the ACTIVITY_EMBEDDING
+ // permission
+ if (mService.checkPermission(ACTIVITY_EMBEDDING, -1, hostUid) == PERMISSION_GRANTED) {
+ return true;
+ }
+
+ // Allowing embedding if it is from the same app that owned the task
+ return hostUid == embeddedUid;
+ }
+
+ /**
* Prepare the target task to be reused for this launch, which including:
* - Position the target task on valid root task on preferred display.
* - Comply to the specified activity launch flags
@@ -2736,31 +2768,6 @@
mIntentDelivered = true;
}
- /**
- * Return {@code true} if the {@param task} has child {@code TaskFragment}s and the
- * {@param activity} can be embedded in. Otherwise, return {@code false}
- */
- private boolean canActivityBeEmbedded(@NonNull ActivityRecord activity, @NonNull Task task) {
- if (task.isLeafTaskFragment()) {
- return false;
- }
-
- final int taskUid = task.effectiveUid;
- // Allowing the activity be embedded into leaf TaskFragment if the task is owned by system.
- if (taskUid == Process.SYSTEM_UID) {
- return true;
- }
-
- // Allowing embedding if the task is owned by an app that has the ACTIVITY_EMBEDDING
- // permission
- if (mService.checkPermission(ACTIVITY_EMBEDDING, -1, taskUid) == PERMISSION_GRANTED) {
- return true;
- }
-
- // Allowing embedding if the activity is from the same app that owned the task
- return activity.isUid(taskUid);
- }
-
private void addOrReparentStartingActivity(@NonNull Task task, String reason) {
TaskFragment newParent = task;
if (mInTaskFragment != null) {
@@ -2772,7 +2779,7 @@
} else {
newParent = mInTaskFragment;
}
- } else if (canActivityBeEmbedded(mStartActivity, task)) {
+ } else {
// Use the child TaskFragment (if any) as the new parent if the activity can be embedded
final ActivityRecord top = task.topRunningActivity();
newParent = top != null ? top.getTaskFragment() : task;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 1759cde..5174a38 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -621,4 +621,7 @@
*/
public abstract boolean hasSystemAlertWindowPermission(int callingUid, int callingPid,
String callingPackage);
+
+ /** Called when the device is waking up */
+ public abstract void notifyWakingUp();
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 381d695..83c83e7 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -64,6 +64,7 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.TRANSIT_NONE;
+import static android.view.WindowManager.TRANSIT_WAKE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
@@ -6506,6 +6507,13 @@
return ActivityTaskManagerService.this.hasSystemAlertWindowPermission(callingUid,
callingPid, callingPackage);
}
+
+ @Override
+ public void notifyWakingUp() {
+ // Start a transition for waking. This is needed for showWhenLocked activities.
+ getTransitionController().requestTransitionIfNeeded(TRANSIT_WAKE, 0 /* flags */,
+ null /* trigger */, mRootWindowContainer.getDefaultDisplay());
+ }
}
final class PackageConfigurationUpdaterImpl implements
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index c5fb34c..369e58c 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -61,6 +61,7 @@
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN;
@@ -201,6 +202,7 @@
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
+import android.view.InsetsVisibilities;
import android.view.MagnificationSpec;
import android.view.PrivacyIndicatorBounds;
import android.view.RemoteAnimationDefinition;
@@ -504,11 +506,6 @@
WindowState mCurrentFocus = null;
/**
- * The last focused window that we've notified the client that the focus is changed.
- */
- WindowState mLastFocus = null;
-
- /**
* The foreground app of this display. Windows below this app cannot be the focused window. If
* the user taps on the area outside of the task of the focused app, we will notify AM about the
* new task the user wants to interact with.
@@ -1243,12 +1240,6 @@
// removing from parent.
token.getParent().removeChild(token);
}
- if (token.hasChild(prevDc.mLastFocus)) {
- // If the reparent window token contains previous display's last focus window, means
- // it will end up to gain window focus on the target display, so it should not be
- // notified that it lost focus from the previous display.
- prevDc.mLastFocus = null;
- }
}
addWindowToken(token.token, token);
@@ -3203,9 +3194,6 @@
pw.print(prefix); pw.print("mLayoutSeq="); pw.println(mLayoutSeq);
pw.print(" mCurrentFocus="); pw.println(mCurrentFocus);
- if (mLastFocus != mCurrentFocus) {
- pw.print(" mLastFocus="); pw.println(mLastFocus);
- }
pw.print(" mFocusedApp="); pw.println(mFocusedApp);
if (mFixedRotationLaunchingApp != null) {
pw.println(" mFixedRotationLaunchingApp=" + mFixedRotationLaunchingApp);
@@ -3436,8 +3424,6 @@
}
}
- onWindowFocusChanged(oldFocus, newFocus);
-
int focusChanged = getDisplayPolicy().focusChangedLw(oldFocus, newFocus);
if (imWindowChanged && oldFocus != mInputMethodWindow) {
@@ -3488,7 +3474,6 @@
mWmService.mAccessibilityController));
}
- mLastFocus = mCurrentFocus;
return true;
}
@@ -3496,20 +3481,6 @@
accessibilityController.onWindowFocusChangedNot(getDisplayId());
}
- private static void onWindowFocusChanged(WindowState oldFocus, WindowState newFocus) {
- final Task focusedTask = newFocus != null ? newFocus.getTask() : null;
- final Task unfocusedTask = oldFocus != null ? oldFocus.getTask() : null;
- if (focusedTask == unfocusedTask) {
- return;
- }
- if (focusedTask != null) {
- focusedTask.onWindowFocusChanged(true /* hasFocus */);
- }
- if (unfocusedTask != null) {
- unfocusedTask.onWindowFocusChanged(false /* hasFocus */);
- }
- }
-
/**
* Set the new focused app to this display.
*
@@ -3533,7 +3504,14 @@
}
ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "setFocusedApp %s displayId=%d Callers=%s",
newFocus, getDisplayId(), Debug.getCallers(4));
+ final Task oldTask = mFocusedApp != null ? mFocusedApp.getTask() : null;
+ final Task newTask = newFocus != null ? newFocus.getTask() : null;
mFocusedApp = newFocus;
+ if (oldTask != newTask) {
+ if (oldTask != null) oldTask.onAppFocusChanged(false);
+ if (newTask != null) newTask.onAppFocusChanged(true);
+ }
+
getInputMonitor().setFocusedAppLw(newFocus);
updateTouchExcludeRegion();
return true;
@@ -4229,7 +4207,6 @@
if (DEBUG_INPUT_METHOD) {
Slog.i(TAG_WM, "Desired input method target: " + imFocus);
Slog.i(TAG_WM, "Current focus: " + mCurrentFocus + " displayId=" + mDisplayId);
- Slog.i(TAG_WM, "Last focus: " + mLastFocus + " displayId=" + mDisplayId);
}
if (DEBUG_INPUT_METHOD) {
@@ -5878,7 +5855,9 @@
return false; /* continue */
}
}
-
+ if (nextWindow.isSecureLocked()) {
+ return false; /* continue */
+ }
return true; /* stop, match found */
}
});
@@ -6048,7 +6027,7 @@
class RemoteInsetsControlTarget implements InsetsControlTarget {
private final IDisplayWindowInsetsController mRemoteInsetsController;
- private final InsetsState mRequestedInsetsState = new InsetsState();
+ private final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
RemoteInsetsControlTarget(IDisplayWindowInsetsController controller) {
mRemoteInsetsController = controller;
@@ -6110,15 +6089,11 @@
if (type == ITYPE_IME) {
return getInsetsStateController().getImeSourceProvider().isImeShowing();
}
- return mRequestedInsetsState.getSourceOrDefaultVisibility(type);
+ return mRequestedVisibilities.getVisibility(type);
}
- void updateRequestedVisibility(InsetsState state) {
- for (int i = 0; i < InsetsState.SIZE; i++) {
- final InsetsSource source = state.peekSource(i);
- if (source == null) continue;
- mRequestedInsetsState.addSource(source);
- }
+ void setRequestedVisibilities(InsetsVisibilities requestedVisibilities) {
+ mRequestedVisibilities.set(requestedVisibilities);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 608be86..686472f 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -140,6 +140,7 @@
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
+import android.view.InsetsVisibilities;
import android.view.Surface;
import android.view.View;
import android.view.ViewDebug;
@@ -339,7 +340,7 @@
private int mLastDisableFlags;
private int mLastAppearance;
private int mLastBehavior;
- private final InsetsState mRequestedState = new InsetsState();
+ private InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
private AppearanceRegion[] mLastStatusBarAppearanceRegions;
/** The union of checked bounds while fetching {@link #mStatusBarColorWindows}. */
@@ -2646,6 +2647,7 @@
final WindowState win = winCandidate;
mSystemUiControllingWindow = win;
+ final int displayId = getDisplayId();
final int disableFlags = win.getDisableFlags();
final int opaqueAppearance = updateSystemBarsLw(win, disableFlags);
final WindowState navColorWin = chooseNavigationColorWindowLw(mNavBarColorWindowCandidate,
@@ -2655,9 +2657,9 @@
final int appearance = updateLightNavigationBarLw(win.mAttrs.insetsFlags.appearance,
navColorWin) | opaqueAppearance;
final int behavior = win.mAttrs.insetsFlags.behavior;
+ final String focusedApp = win.mAttrs.packageName;
final boolean isFullscreen = !win.getRequestedVisibility(ITYPE_STATUS_BAR)
|| !win.getRequestedVisibility(ITYPE_NAVIGATION_BAR);
-
final AppearanceRegion[] appearanceRegions =
new AppearanceRegion[mStatusBarColorWindows.size()];
for (int i = mStatusBarColorWindows.size() - 1; i >= 0; i--) {
@@ -2666,12 +2668,16 @@
getStatusBarAppearance(windowState, windowState),
new Rect(windowState.getFrame()));
}
-
- if (mLastDisableFlags == disableFlags
- && mLastAppearance == appearance
+ if (mLastDisableFlags != disableFlags) {
+ mLastDisableFlags = disableFlags;
+ final String cause = win.toString();
+ callStatusBarSafely(statusBar -> statusBar.setDisableFlags(displayId, disableFlags,
+ cause));
+ }
+ if (mLastAppearance == appearance
&& mLastBehavior == behavior
- && mRequestedState.equals(win.getRequestedState())
- && Objects.equals(mFocusedApp, win.mAttrs.packageName)
+ && mRequestedVisibilities.equals(win.getRequestedVisibilities())
+ && Objects.equals(mFocusedApp, focusedApp)
&& mLastFocusIsFullscreen == isFullscreen
&& Arrays.equals(mLastStatusBarAppearanceRegions, appearanceRegions)) {
return false;
@@ -2681,24 +2687,17 @@
mService.mInputManager.setSystemUiLightsOut(
isFullscreen || (appearance & APPEARANCE_LOW_PROFILE_BARS) != 0);
}
- mLastDisableFlags = disableFlags;
+ final InsetsVisibilities requestedVisibilities =
+ new InsetsVisibilities(win.getRequestedVisibilities());
mLastAppearance = appearance;
mLastBehavior = behavior;
- mRequestedState.set(win.getRequestedState(), true /* copySources */);
- mFocusedApp = win.mAttrs.packageName;
+ mRequestedVisibilities = requestedVisibilities;
+ mFocusedApp = focusedApp;
mLastFocusIsFullscreen = isFullscreen;
mLastStatusBarAppearanceRegions = appearanceRegions;
- final String cause = win.toString();
- mHandler.post(() -> {
- StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
- if (statusBar != null) {
- final int displayId = getDisplayId();
- statusBar.setDisableFlags(displayId, disableFlags, cause);
- statusBar.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions,
- isNavbarColorManagedByIme, behavior, mRequestedState, mFocusedApp);
-
- }
- });
+ callStatusBarSafely(statusBar -> statusBar.onSystemBarAttributesChanged(displayId,
+ appearance, appearanceRegions, isNavbarColorManagedByIme, behavior,
+ requestedVisibilities, focusedApp));
return true;
}
@@ -2710,6 +2709,15 @@
: 0;
}
+ private void callStatusBarSafely(Consumer<StatusBarManagerInternal> consumer) {
+ mHandler.post(() -> {
+ StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
+ if (statusBar != null) {
+ consumer.accept(statusBar);
+ }
+ });
+ }
+
@VisibleForTesting
@Nullable
static WindowState chooseNavigationColorWindowLw(WindowState candidate, WindowState imeWindow,
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 6b126ca..0a83784 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -133,12 +133,19 @@
abortTransient();
}
mFocusedWin = focusedWin;
- InsetsControlTarget statusControlTarget = getStatusControlTarget(focusedWin);
- InsetsControlTarget navControlTarget = getNavControlTarget(focusedWin);
- mStateController.onBarControlTargetChanged(statusControlTarget,
- getFakeControlTarget(focusedWin, statusControlTarget),
+ final InsetsControlTarget statusControlTarget =
+ getStatusControlTarget(focusedWin, false /* fake */);
+ final InsetsControlTarget navControlTarget =
+ getNavControlTarget(focusedWin, false /* fake */);
+ mStateController.onBarControlTargetChanged(
+ statusControlTarget,
+ statusControlTarget == mDummyControlTarget
+ ? getStatusControlTarget(focusedWin, true /* fake */)
+ : null,
navControlTarget,
- getFakeControlTarget(focusedWin, navControlTarget));
+ navControlTarget == mDummyControlTarget
+ ? getNavControlTarget(focusedWin, true /* fake */)
+ : null);
mStatusBar.updateVisibility(statusControlTarget, ITYPE_STATUS_BAR);
mNavBar.updateVisibility(navControlTarget, ITYPE_NAVIGATION_BAR);
}
@@ -294,13 +301,9 @@
mShowingTransientTypes.clear();
}
- private @Nullable InsetsControlTarget getFakeControlTarget(@Nullable WindowState focused,
- InsetsControlTarget realControlTarget) {
- return realControlTarget == mDummyControlTarget ? focused : null;
- }
-
- private @Nullable InsetsControlTarget getStatusControlTarget(@Nullable WindowState focusedWin) {
- if (mShowingTransientTypes.indexOf(ITYPE_STATUS_BAR) != -1) {
+ private @Nullable InsetsControlTarget getStatusControlTarget(@Nullable WindowState focusedWin,
+ boolean fake) {
+ if (mShowingTransientTypes.indexOf(ITYPE_STATUS_BAR) != -1 && !fake) {
return mDummyControlTarget;
}
final WindowState notificationShade = mPolicy.getNotificationShade();
@@ -318,7 +321,7 @@
// we will dispatch the real visibility of status bar to the client.
return null;
}
- if (forceShowsStatusBarTransiently()) {
+ if (forceShowsStatusBarTransiently() && !fake) {
// Status bar is forcibly shown transiently, and its new visibility won't be
// dispatched to the client so that we can keep the layout stable. We will dispatch the
// fake control to the client, so that it can re-show the bar during this scenario.
@@ -343,13 +346,14 @@
&& !win.inMultiWindowMode();
}
- private @Nullable InsetsControlTarget getNavControlTarget(@Nullable WindowState focusedWin) {
+ private @Nullable InsetsControlTarget getNavControlTarget(@Nullable WindowState focusedWin,
+ boolean fake) {
final WindowState imeWin = mDisplayContent.mInputMethodWindow;
if (imeWin != null && imeWin.isVisible()) {
// Force showing navigation bar while IME is visible.
return null;
}
- if (mShowingTransientTypes.indexOf(ITYPE_NAVIGATION_BAR) != -1) {
+ if (mShowingTransientTypes.indexOf(ITYPE_NAVIGATION_BAR) != -1 && !fake) {
return mDummyControlTarget;
}
if (focusedWin == mPolicy.getNotificationShade()) {
@@ -366,7 +370,7 @@
// bar, and we will dispatch the real visibility of navigation bar to the client.
return null;
}
- if (forceShowsNavigationBarTransiently()) {
+ if (forceShowsNavigationBarTransiently() && !fake) {
// Navigation bar is forcibly shown transiently, and its new visibility won't be
// dispatched to the client so that we can keep the layout stable. We will dispatch the
// fake control to the client, so that it can re-show the bar during this scenario.
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 672ebf1..9cd8c2d 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -49,6 +49,7 @@
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
+import android.view.WindowManager;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.server.inputmethod.InputMethodManagerInternal;
@@ -158,6 +159,7 @@
final boolean keyguardChanged = (keyguardShowing != mKeyguardShowing)
|| (mKeyguardGoingAway && keyguardShowing && !aodChanged);
if (!keyguardChanged && !aodChanged) {
+ setWakeTransitionReady();
return;
}
EventLogTags.writeWmSetKeyguardShown(
@@ -203,6 +205,15 @@
updateKeyguardSleepToken();
mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
InputMethodManagerInternal.get().updateImeWindowStatus(false /* disableImeIcon */);
+ setWakeTransitionReady();
+ }
+
+ private void setWakeTransitionReady() {
+ if (mWindowManager.mAtmService.getTransitionController().getCollectingTransitionType()
+ == WindowManager.TRANSIT_WAKE) {
+ mWindowManager.mAtmService.getTransitionController().setReady(
+ mRootWindowContainer.getDefaultDisplay());
+ }
}
/**
@@ -334,6 +345,7 @@
for (int displayNdx = mRootWindowContainer.getChildCount() - 1;
displayNdx >= 0; displayNdx--) {
final DisplayContent display = mRootWindowContainer.getChildAt(displayNdx);
+ if (display.isRemoving() || display.isRemoved()) continue;
final KeyguardDisplayState state = getDisplayState(display.mDisplayId);
state.updateVisibility(this, display);
requestDismissKeyguard |= state.mRequestDismissKeyguard;
diff --git a/services/core/java/com/android/server/wm/PinnedTaskController.java b/services/core/java/com/android/server/wm/PinnedTaskController.java
index 7e95e7d..4f7c9a4 100644
--- a/services/core/java/com/android/server/wm/PinnedTaskController.java
+++ b/services/core/java/com/android/server/wm/PinnedTaskController.java
@@ -211,7 +211,9 @@
}
mFreezingTaskConfig = true;
mDestRotatedBounds = new Rect(bounds);
- continueOrientationChange();
+ if (!mService.mAtmService.getTransitionController().isShellTransitionsEnabled()) {
+ continueOrientationChange();
+ }
}
/**
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 455f568..ede4c2e 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1108,13 +1108,15 @@
}
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: trimming tasks for " + task);
- removeForAddTask(task);
+ final int removedIndex = removeForAddTask(task);
task.inRecents = true;
if (!isAffiliated || needAffiliationFix) {
// If this is a simple non-affiliated task, or we had some failure trying to
// handle it as part of an affilated task, then just place it at the top.
- mTasks.add(0, task);
+ // But if the list is frozen, adding the task to the removed index to keep the order.
+ int indexToAdd = mFreezeTaskListReordering && removedIndex != -1 ? removedIndex : 0;
+ mTasks.add(indexToAdd, task);
notifyTaskAdded(task);
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding " + task);
} else if (isAffiliated) {
@@ -1482,14 +1484,14 @@
* If needed, remove oldest existing entries in recents that are for the same kind
* of task as the given one.
*/
- private void removeForAddTask(Task task) {
+ private int removeForAddTask(Task task) {
// The adding task will be in recents so it is not hidden.
mHiddenTasks.remove(task);
final int removeIndex = findRemoveIndexForAddTask(task);
if (removeIndex == -1) {
// Nothing to trim
- return;
+ return removeIndex;
}
// There is a similar task that will be removed for the addition of {@param task}, but it
@@ -1511,6 +1513,7 @@
}
}
notifyTaskPersisterLocked(removedTask, false /* flush */);
+ return removeIndex;
}
/**
@@ -1518,11 +1521,6 @@
* list (if any).
*/
private int findRemoveIndexForAddTask(Task task) {
- if (mFreezeTaskListReordering) {
- // Defer removing tasks due to the addition of new tasks until the task list is unfrozen
- return -1;
- }
-
final int recentsCount = mTasks.size();
final Intent intent = task.intent;
final boolean document = intent != null && intent.isDocument();
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 629d20e..24c5c82 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2157,7 +2157,7 @@
rootTask.setLastRecentsAnimationTransaction(
task.mLastRecentsAnimationTransaction,
task.mLastRecentsAnimationOverlay);
- task.clearLastRecentsAnimationTransaction();
+ task.clearLastRecentsAnimationTransaction(false /* forceRemoveOverlay */);
}
// There are multiple activities in the task and moving the top activity should
@@ -2212,16 +2212,17 @@
ensureActivitiesVisible(null, 0, false /* preserveWindows */);
resumeFocusedTasksTopActivities();
- notifyActivityPipModeChanged(r);
+ notifyActivityPipModeChanged(r.getTask(), r);
}
/**
* Notifies when an activity enters or leaves PIP mode.
*
+ * @param task the task of {@param r}
* @param r indicates the activity currently in PIP, can be null to indicate no activity is
* currently in PIP mode.
*/
- void notifyActivityPipModeChanged(@Nullable ActivityRecord r) {
+ void notifyActivityPipModeChanged(@NonNull Task task, @Nullable ActivityRecord r) {
final boolean inPip = r != null;
if (inPip) {
mService.getTaskChangeNotificationController().notifyActivityPinned(r);
@@ -2229,6 +2230,9 @@
mService.getTaskChangeNotificationController().notifyActivityUnpinned();
}
mWindowManager.mPolicy.setPipVisibilityLw(inPip);
+ mWmService.mTransactionFactory.get()
+ .setTrustedOverlay(task.getSurfaceControl(), inPip)
+ .apply();
}
void executeAppTransitionForAllDisplay() {
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index e282012..0b56777 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -69,6 +69,7 @@
import android.view.InputChannel;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.WindowManager;
@@ -113,7 +114,7 @@
private float mLastReportedAnimatorScale;
private String mPackageName;
private String mRelayoutTag;
- private final InsetsState mDummyRequestedVisibility = new InsetsState();
+ private final InsetsVisibilities mDummyRequestedVisibilities = new InsetsVisibilities();
private final InsetsSourceControl[] mDummyControls = new InsetsSourceControl[0];
public Session(WindowManagerService service, IWindowSessionCallback callback) {
@@ -187,29 +188,28 @@
@Override
public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs,
- int viewVisibility, int displayId, InsetsState requestedVisibility,
+ int viewVisibility, int displayId, InsetsVisibilities requestedVisibilities,
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
return mService.addWindow(this, window, attrs, viewVisibility, displayId,
- UserHandle.getUserId(mUid), requestedVisibility, outInputChannel, outInsetsState,
+ UserHandle.getUserId(mUid), requestedVisibilities, outInputChannel, outInsetsState,
outActiveControls);
}
-
@Override
public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
- int viewVisibility, int displayId, int userId, InsetsState requestedVisibility,
+ int viewVisibility, int displayId, int userId, InsetsVisibilities requestedVisibilities,
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId,
- requestedVisibility, outInputChannel, outInsetsState, outActiveControls);
+ requestedVisibilities, outInputChannel, outInsetsState, outActiveControls);
}
@Override
public int addToDisplayWithoutInputChannel(IWindow window, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, InsetsState outInsetsState) {
return mService.addWindow(this, window, attrs, viewVisibility, displayId,
- UserHandle.getUserId(mUid), mDummyRequestedVisibility, null /* outInputChannel */,
+ UserHandle.getUserId(mUid), mDummyRequestedVisibilities, null /* outInputChannel */,
outInsetsState, mDummyControls);
}
@@ -624,12 +624,12 @@
}
@Override
- public void insetsModified(IWindow window, InsetsState state) {
+ public void updateRequestedVisibilities(IWindow window, InsetsVisibilities visibilities) {
synchronized (mService.mGlobalLock) {
final WindowState windowState = mService.windowForClientLocked(this, window,
false /* throwOnError */);
if (windowState != null) {
- windowState.updateRequestedVisibility(state);
+ windowState.setRequestedVisibilities(visibilities);
windowState.getDisplayContent().getInsetsPolicy().onInsetsModified(windowState);
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 5ffe7b6..2355dde 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -180,7 +180,6 @@
import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
import android.view.RemoteAnimationAdapter;
-import android.view.RemoteAnimationTarget;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.WindowManager;
@@ -1203,7 +1202,7 @@
&& (newParent == null || !newParent.inPinnedWindowingMode())) {
// Notify if a task from the root pinned task is being removed
// (or moved depending on the mode).
- mRootWindowContainer.notifyActivityPipModeChanged(null);
+ mRootWindowContainer.notifyActivityPipModeChanged(this, null);
}
}
@@ -3031,18 +3030,6 @@
return isAnimating(CHILDREN, ANIMATION_TYPE_RECENTS);
}
- @Override
- RemoteAnimationTarget createRemoteAnimationTarget(
- RemoteAnimationController.RemoteAnimationRecord record) {
- final ActivityRecord activity = getTopMostActivity();
- return activity != null ? activity.createRemoteAnimationTarget(record) : null;
- }
-
- @Override
- boolean canCreateRemoteAnimationTarget() {
- return true;
- }
-
WindowState getTopVisibleAppMainWindow() {
final ActivityRecord activity = getTopVisibleActivity();
return activity != null ? activity.findMainWindow() : null;
@@ -3527,7 +3514,9 @@
StartingWindowInfo getStartingWindowInfo(ActivityRecord activity) {
final StartingWindowInfo info = new StartingWindowInfo();
info.taskInfo = getTaskInfo();
-
+ info.targetActivityInfo = info.taskInfo.topActivityInfo != null
+ && activity.info != info.taskInfo.topActivityInfo
+ ? activity.info : null;
info.isKeyguardOccluded =
mAtmService.mKeyguardController.isDisplayOccluded(DEFAULT_DISPLAY);
@@ -4327,10 +4316,10 @@
* @return true if the task is currently focused.
*/
private boolean isFocused() {
- if (mDisplayContent == null || mDisplayContent.mCurrentFocus == null) {
+ if (mDisplayContent == null || mDisplayContent.mFocusedApp == null) {
return false;
}
- return mDisplayContent.mCurrentFocus.getTask() == this;
+ return mDisplayContent.mFocusedApp.getTask() == this;
}
/**
@@ -4387,10 +4376,9 @@
* Called on the task of a window which gained or lost focus.
* @param hasFocus
*/
- void onWindowFocusChanged(boolean hasFocus) {
+ void onAppFocusChanged(boolean hasFocus) {
updateShadowsRadius(hasFocus, getSyncTransaction());
- // TODO(b/180525887): Un-comment once there is resolution on the bug.
- // dispatchTaskInfoChangedIfNeeded(false /* force */);
+ dispatchTaskInfoChangedIfNeeded(false /* force */);
}
void onPictureInPictureParamsChanged() {
@@ -4576,7 +4564,7 @@
: WINDOWING_MODE_FULLSCREEN;
}
if (currentMode == WINDOWING_MODE_PINNED) {
- mRootWindowContainer.notifyActivityPipModeChanged(null);
+ mRootWindowContainer.notifyActivityPipModeChanged(this, null);
}
if (likelyResolvedMode == WINDOWING_MODE_PINNED) {
// In the case that we've disabled affecting the SysUI flags as a part of seamlessly
@@ -4634,7 +4622,8 @@
// From fullscreen to PiP.
if (topActivity != null && currentMode == WINDOWING_MODE_FULLSCREEN
- && windowingMode == WINDOWING_MODE_PINNED) {
+ && windowingMode == WINDOWING_MODE_PINNED
+ && !mAtmService.getTransitionController().isShellTransitionsEnabled()) {
mDisplayContent.mPinnedTaskController
.deferOrientationChangeForEnteringPipFromFullScreenIfNeeded();
}
@@ -6042,7 +6031,10 @@
mLastRecentsAnimationOverlay = overlay;
}
- void clearLastRecentsAnimationTransaction() {
+ void clearLastRecentsAnimationTransaction(boolean forceRemoveOverlay) {
+ if (forceRemoveOverlay && mLastRecentsAnimationOverlay != null) {
+ getPendingTransaction().remove(mLastRecentsAnimationOverlay);
+ }
mLastRecentsAnimationTransaction = null;
mLastRecentsAnimationOverlay = null;
// reset also the crop and transform introduced by mLastRecentsAnimationTransaction
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 10c16ff..6c8cde43 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -780,10 +780,12 @@
}
return SCREEN_ORIENTATION_UNSPECIFIED;
} else {
- // Apps and their containers are not allowed to specify an orientation of full screen
- // tasks created by organizer. The organizer handles the orientation instead.
- final Task task = getTopRootTaskInWindowingMode(WINDOWING_MODE_FULLSCREEN);
- if (task != null && task.isVisible() && task.mCreatedByOrganizer) {
+ // Apps and their containers are not allowed to specify an orientation of non floating
+ // visible tasks created by organizer. The organizer handles the orientation instead.
+ final Task nonFloatingTopTask =
+ getRootTask(t -> !t.getWindowConfiguration().tasksAreFloating());
+ if (nonFloatingTopTask != null && nonFloatingTopTask.mCreatedByOrganizer
+ && nonFloatingTopTask.isVisible()) {
return SCREEN_ORIENTATION_UNSPECIFIED;
}
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 9159bbb..1eec6aa 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -83,9 +83,11 @@
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
+import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.window.ITaskFragmentOrganizer;
import android.window.TaskFragmentInfo;
+import android.window.TaskFragmentOrganizerToken;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
@@ -285,8 +287,8 @@
taskFragment.mAdjacentTaskFragment = this;
}
- void setTaskFragmentOrganizer(ITaskFragmentOrganizer organizer, int pid) {
- mTaskFragmentOrganizer = organizer;
+ void setTaskFragmentOrganizer(TaskFragmentOrganizerToken organizer, int pid) {
+ mTaskFragmentOrganizer = ITaskFragmentOrganizer.Stub.asInterface(organizer.asBinder());
mTaskFragmentOrganizerPid = pid;
}
@@ -1486,6 +1488,18 @@
// No app transition applied to the task fragment.
}
+ @Override
+ RemoteAnimationTarget createRemoteAnimationTarget(
+ RemoteAnimationController.RemoteAnimationRecord record) {
+ final ActivityRecord activity = getTopMostActivity();
+ return activity != null ? activity.createRemoteAnimationTarget(record) : null;
+ }
+
+ @Override
+ boolean canCreateRemoteAnimationTarget() {
+ return true;
+ }
+
boolean shouldSleepActivities() {
return false;
}
@@ -1895,6 +1909,7 @@
mRemoteToken.toWindowContainerToken(),
getConfiguration(),
getChildCount() == 0,
+ hasRunningActivity(this),
isVisible(),
childActivities,
positionInParent);
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 496ecde..a322384 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.window.TaskFragmentOrganizer.putExceptionInBundle;
+
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer;
@@ -23,6 +25,7 @@
import android.annotation.Nullable;
import android.content.res.Configuration;
import android.os.Binder;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArrayMap;
@@ -113,8 +116,11 @@
}
void dispose() {
- mOrganizedTaskFragments.forEach(TaskFragment::removeImmediately);
- mOrganizedTaskFragments.clear();
+ while (!mOrganizedTaskFragments.isEmpty()) {
+ final TaskFragment taskFragment = mOrganizedTaskFragments.get(0);
+ taskFragment.removeImmediately();
+ mOrganizedTaskFragments.remove(taskFragment);
+ }
mOrganizer.asBinder().unlinkToDeath(this, 0 /*flags*/);
}
@@ -190,6 +196,16 @@
Slog.e(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e);
}
}
+
+ void onTaskFragmentError(ITaskFragmentOrganizer organizer, IBinder errorCallbackToken,
+ Throwable exception) {
+ final Bundle exceptionBundle = putExceptionInBundle(exception);
+ try {
+ organizer.onTaskFragmentError(errorCallbackToken, exceptionBundle);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception sending onTaskFragmentError callback", e);
+ }
+ }
}
@Override
@@ -289,6 +305,14 @@
state.removeTaskFragment(taskFragment);
}
+ void onTaskFragmentError(ITaskFragmentOrganizer organizer, IBinder errorCallbackToken,
+ Throwable exception) {
+ validateAndGetState(organizer);
+ PendingTaskFragmentEvent pendingEvent = new PendingTaskFragmentEvent(organizer,
+ errorCallbackToken, exception, PendingTaskFragmentEvent.EVENT_ERROR);
+ mPendingTaskFragmentEvents.add(pendingEvent);
+ }
+
private void removeOrganizer(ITaskFragmentOrganizer organizer) {
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
// remove all of the children of the organized TaskFragment
@@ -321,25 +345,45 @@
static final int EVENT_VANISHED = 1;
static final int EVENT_INFO_CHANGED = 2;
static final int EVENT_PARENT_INFO_CHANGED = 3;
+ static final int EVENT_ERROR = 4;
@IntDef(prefix = "EVENT_", value = {
EVENT_APPEARED,
EVENT_VANISHED,
EVENT_INFO_CHANGED,
- EVENT_PARENT_INFO_CHANGED
+ EVENT_PARENT_INFO_CHANGED,
+ EVENT_ERROR
})
@Retention(RetentionPolicy.SOURCE)
public @interface EventType {}
@EventType
- final int mEventType;
- final TaskFragment mTaskFragment;
- final ITaskFragmentOrganizer mTaskFragmentOrg;
+ private final int mEventType;
+ private final ITaskFragmentOrganizer mTaskFragmentOrg;
+ private final TaskFragment mTaskFragment;
+ private final IBinder mErrorCallback;
+ private final Throwable mException;
- PendingTaskFragmentEvent(TaskFragment taskFragment, ITaskFragmentOrganizer taskFragmentOrg,
+ private PendingTaskFragmentEvent(TaskFragment taskFragment,
+ ITaskFragmentOrganizer taskFragmentOrg, @EventType int eventType) {
+ this(taskFragment, taskFragmentOrg, null /* errorCallback */,
+ null /* exception */, eventType);
+
+ }
+
+ private PendingTaskFragmentEvent(ITaskFragmentOrganizer taskFragmentOrg,
+ IBinder errorCallback, Throwable exception, @EventType int eventType) {
+ this(null /* taskFragment */, taskFragmentOrg, errorCallback, exception,
+ eventType);
+ }
+
+ private PendingTaskFragmentEvent(TaskFragment taskFragment,
+ ITaskFragmentOrganizer taskFragmentOrg, IBinder errorCallback, Throwable exception,
@EventType int eventType) {
mTaskFragment = taskFragment;
mTaskFragmentOrg = taskFragmentOrg;
+ mErrorCallback = errorCallback;
+ mException = exception;
mEventType = eventType;
}
@@ -407,6 +451,10 @@
break;
case PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED:
state.onTaskFragmentParentInfoChanged(taskFragmentOrg, taskFragment);
+ break;
+ case PendingTaskFragmentEvent.EVENT_ERROR:
+ state.onTaskFragmentError(taskFragmentOrg, event.mErrorCallback,
+ event.mException);
}
}
mPendingTaskFragmentEvents.clear();
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index cc4abab..059eb87 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -72,6 +72,7 @@
import android.view.IWindowSession;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.View;
@@ -166,6 +167,7 @@
final ClientWindowFrames tmpFrames = new ClientWindowFrames();
final Rect taskBounds;
final InsetsState mTmpInsetsState = new InsetsState();
+ final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0];
final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
final TaskDescription taskDescription = new TaskDescription();
@@ -227,7 +229,8 @@
int displayId = activity.getDisplayContent().getDisplayId();
try {
final int res = session.addToDisplay(window, layoutParams, View.GONE, displayId,
- mTmpInsetsState, null /* outInputChannel */, mTmpInsetsState, mTempControls);
+ mRequestedVisibilities, null /* outInputChannel */, mTmpInsetsState,
+ mTempControls);
if (res < 0) {
Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
return null;
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 2c17b73..43165f8 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -33,6 +33,8 @@
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.view.WindowManager.TransitionFlags;
+import static android.view.WindowManager.TransitionType;
import static android.view.WindowManager.transitTypeToString;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static android.window.TransitionInfo.FLAG_IS_VOICE_INTERACTION;
@@ -59,7 +61,6 @@
import android.util.ArraySet;
import android.util.Slog;
import android.view.SurfaceControl;
-import android.view.WindowManager;
import android.view.animation.Animation;
import android.window.IRemoteTransition;
import android.window.TransitionInfo;
@@ -109,9 +110,9 @@
@Retention(RetentionPolicy.SOURCE)
@interface TransitionState {}
- final @WindowManager.TransitionType int mType;
+ final @TransitionType int mType;
private int mSyncId;
- private @WindowManager.TransitionFlags int mFlags;
+ private @TransitionFlags int mFlags;
private final TransitionController mController;
private final BLASTSyncEngine mSyncEngine;
private IRemoteTransition mRemoteTransition = null;
@@ -146,7 +147,7 @@
private boolean mNavBarAttachedToApp = false;
private int mNavBarDisplayId = INVALID_DISPLAY;
- Transition(@WindowManager.TransitionType int type, @WindowManager.TransitionFlags int flags,
+ Transition(@TransitionType int type, @TransitionFlags int flags,
TransitionController controller, BLASTSyncEngine syncEngine) {
mType = type;
mFlags = flags;
@@ -617,7 +618,7 @@
}
private void handleNonAppWindowsInTransition(int displayId,
- @WindowManager.TransitionType int transit, int flags) {
+ @TransitionType int transit, int flags) {
final DisplayContent dc =
mController.mAtm.mRootWindowContainer.getDisplayContent(displayId);
if (dc == null) {
@@ -968,7 +969,7 @@
*/
@VisibleForTesting
@NonNull
- static TransitionInfo calculateTransitionInfo(int type, int flags,
+ static TransitionInfo calculateTransitionInfo(@TransitionType int type, int flags,
ArraySet<WindowContainer> targets, ArrayMap<WindowContainer, ChangeInfo> changes) {
final TransitionInfo out = new TransitionInfo(type, flags);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a4db2dc..7f6dce4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -249,6 +249,7 @@
import android.view.InputWindowHandle;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.KeyEvent;
import android.view.MagnificationSpec;
import android.view.MotionEvent;
@@ -451,14 +452,14 @@
/**
* @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
*/
- public static final boolean sEnableRemoteKeyguardGoingAwayAnimation = !sEnableShellTransitions
- && sEnableRemoteKeyguardAnimation >= 1;
+ public static final boolean sEnableRemoteKeyguardGoingAwayAnimation =
+ sEnableRemoteKeyguardAnimation >= 1;
/**
* @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
*/
- public static final boolean sEnableRemoteKeyguardOccludeAnimation = !sEnableShellTransitions
- && sEnableRemoteKeyguardAnimation >= 2;
+ public static final boolean sEnableRemoteKeyguardOccludeAnimation =
+ sEnableRemoteKeyguardAnimation >= 2;
/**
* Allows a fullscreen windowing mode activity to launch in its desired orientation directly
@@ -1456,7 +1457,7 @@
}
public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
- int displayId, int requestUserId, InsetsState requestedVisibility,
+ int displayId, int requestUserId, InsetsVisibilities requestedVisibilities,
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
Arrays.fill(outActiveControls, null);
@@ -1678,7 +1679,7 @@
final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
displayPolicy.adjustWindowParamsLw(win, win.mAttrs);
- win.updateRequestedVisibility(requestedVisibility);
+ win.setRequestedVisibilities(requestedVisibilities);
res = displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid);
if (res != ADD_OKAY) {
@@ -4158,7 +4159,7 @@
}
@Override
- public void modifyDisplayWindowInsets(int displayId, InsetsState state) {
+ public void updateDisplayWindowRequestedVisibilities(int displayId, InsetsVisibilities vis) {
if (mContext.checkCallingOrSelfPermission(MANAGE_APP_TOKENS)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Must hold permission " + MANAGE_APP_TOKENS);
@@ -4170,7 +4171,7 @@
if (dc == null || dc.mRemoteInsetsControlTarget == null) {
return;
}
- dc.mRemoteInsetsControlTarget.updateRequestedVisibility(state);
+ dc.mRemoteInsetsControlTarget.setRequestedVisibilities(vis);
dc.getInsetsStateController().onInsetsModified(dc.mRemoteInsetsControlTarget);
}
} finally {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 58f7a55..abf8afa 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.app.ActivityManager.isStartResultSuccessful;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
@@ -28,6 +29,7 @@
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_CHILDREN;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
@@ -44,6 +46,7 @@
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.WindowConfiguration;
+import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -369,7 +372,8 @@
final boolean isInLockTaskMode = mService.isInLockTaskMode();
for (int i = 0; i < hopSize; ++i) {
effects |= applyHierarchyOp(hops.get(i), effects, syncId, transition,
- isInLockTaskMode, caller);
+ isInLockTaskMode, caller, t.getErrorCallbackToken(),
+ t.getTaskFragmentOrganizer());
}
}
// Queue-up bounds-change transactions for tasks which are now organized. Do
@@ -525,7 +529,8 @@
private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,
int syncId, @Nullable Transition transition, boolean isInLockTaskMode,
- @Nullable CallerInfo caller) {
+ @Nullable CallerInfo caller, @Nullable IBinder errorCallbackToken,
+ @Nullable ITaskFragmentOrganizer organizer) {
final int type = hop.getType();
switch (type) {
case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: {
@@ -652,7 +657,7 @@
case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT:
final TaskFragmentCreationParams taskFragmentCreationOptions =
hop.getTaskFragmentCreationOptions();
- createTaskFragment(taskFragmentCreationOptions);
+ createTaskFragment(taskFragmentCreationOptions, errorCallbackToken);
break;
case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT:
wc = WindowContainer.fromBinder(hop.getContainer());
@@ -665,28 +670,37 @@
throw new IllegalArgumentException(
"Can only delete organized TaskFragment, but not Task.");
}
- deleteTaskFragment(taskFragment);
+ deleteTaskFragment(taskFragment, errorCallbackToken);
break;
case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
fragmentToken = hop.getContainer();
if (!mLaunchTaskFragments.containsKey(fragmentToken)) {
- throw new IllegalArgumentException(
+ final Throwable exception = new IllegalArgumentException(
"Not allowed to operate with invalid fragment token");
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
+ break;
}
final Intent activityIntent = hop.getActivityIntent();
final Bundle activityOptions = hop.getLaunchOptions();
- mService.getActivityStartController()
- .startActivityInTaskFragment(mLaunchTaskFragments.get(fragmentToken),
- activityIntent, activityOptions);
- // TODO(b/189385246) : report the failure back to the organizer if the activity
- // start failed
+ final TaskFragment tf = mLaunchTaskFragments.get(fragmentToken);
+ final int result = mService.getActivityStartController()
+ .startActivityInTaskFragment(tf, activityIntent, activityOptions,
+ hop.getCallingActivity());
+ if (!isStartResultSuccessful(result)) {
+ final Throwable exception =
+ new ActivityNotFoundException("start activity in taskFragment failed");
+ sendTaskFragmentOperationFailure(tf.getTaskFragmentOrganizer(),
+ errorCallbackToken, exception);
+ }
break;
case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT:
fragmentToken = hop.getNewParent();
final ActivityRecord activity = ActivityRecord.forTokenLocked(hop.getContainer());
if (!mLaunchTaskFragments.containsKey(fragmentToken) || activity == null) {
- throw new IllegalArgumentException(
+ final Throwable exception = new IllegalArgumentException(
"Not allowed to operate with invalid fragment token or activity.");
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
+ break;
}
activity.reparent(mLaunchTaskFragments.get(fragmentToken), POSITION_TOP);
break;
@@ -700,7 +714,20 @@
+ oldParent);
break;
}
- reparentTaskFragment(oldParent, newParent);
+ reparentTaskFragment(oldParent, newParent, errorCallbackToken);
+ break;
+ case HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS:
+ fragmentToken = hop.getContainer();
+ final IBinder adjacentFragmentToken = hop.getAdjacentRoot();
+ final TaskFragment tf1 = mLaunchTaskFragments.get(fragmentToken);
+ final TaskFragment tf2 = mLaunchTaskFragments.get(adjacentFragmentToken);
+ if (tf1 == null || tf2 == null) {
+ final Throwable exception = new IllegalArgumentException(
+ "Not allowed to set adjacent on invalid fragment tokens");
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
+ break;
+ }
+ tf1.setAdjacentTaskFragment(tf2);
break;
}
return effects;
@@ -1034,9 +1061,11 @@
// valid.
case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT:
+ case HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS:
// We are allowing organizer to start/reparent activity to a TaskFragment it
- // created. Nothing to check here because the TaskFragment may not be created
- // yet, but will be created in the same transaction.
+ // created, or set two TaskFragments adjacent to each other. Nothing to check
+ // here because the TaskFragment may not be created yet, but will be created in
+ // the same transaction.
break;
case HIERARCHY_OP_TYPE_REPARENT_CHILDREN:
enforceTaskFragmentOrganized(func,
@@ -1076,17 +1105,26 @@
}
}
- void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams) {
+ void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams,
+ @Nullable IBinder errorCallbackToken) {
final ActivityRecord ownerActivity =
ActivityRecord.forTokenLocked(creationParams.getOwnerToken());
+ final ITaskFragmentOrganizer organizer = ITaskFragmentOrganizer.Stub.asInterface(
+ creationParams.getOrganizer().asBinder());
+
if (ownerActivity == null || ownerActivity.getTask() == null) {
- // TODO(b/189385246) : report the failure back to the organizer
+ final Throwable exception =
+ new IllegalArgumentException("Not allowed to operate with invalid ownerToken");
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
return;
}
// The ownerActivity has to belong to the same app as the root Activity of the target Task.
final ActivityRecord rootActivity = ownerActivity.getTask().getRootActivity();
if (rootActivity.getUid() != ownerActivity.getUid()) {
- // TODO(b/189385246) : report the failure back to the organizer
+ final Throwable exception =
+ new IllegalArgumentException("Not allowed to operate with the ownerToken while "
+ + "the root activity of the target task belong to the different app");
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
return;
}
final TaskFragment taskFragment = new TaskFragment(mService,
@@ -1102,13 +1140,16 @@
}
void reparentTaskFragment(@NonNull WindowContainer oldParent,
- @Nullable WindowContainer newParent) {
+ @Nullable WindowContainer newParent, @Nullable IBinder errorCallbackToken) {
WindowContainer parent = newParent;
if (parent == null && oldParent.asTaskFragment() != null) {
parent = oldParent.asTaskFragment().getTask();
}
if (parent == null) {
- // TODO(b/189385246) : report the failure back to the organizer
+ final Throwable exception =
+ new IllegalArgumentException("Not allowed to operate with invalid container");
+ sendTaskFragmentOperationFailure(oldParent.asTaskFragment().getTaskFragmentOrganizer(),
+ errorCallbackToken, exception);
return;
}
while (oldParent.hasChild()) {
@@ -1116,11 +1157,16 @@
}
}
- void deleteTaskFragment(@NonNull TaskFragment taskFragment) {
+ void deleteTaskFragment(@NonNull TaskFragment taskFragment,
+ @Nullable IBinder errorCallbackToken) {
final int index = mLaunchTaskFragments.indexOfValue(taskFragment);
if (index < 0) {
- throw new IllegalArgumentException(
- "Not allowed to operate with invalid taskFragment");
+ final Throwable exception =
+ new IllegalArgumentException("Not allowed to operate with invalid "
+ + "taskFragment");
+ sendTaskFragmentOperationFailure(taskFragment.getTaskFragmentOrganizer(),
+ errorCallbackToken, exception);
+ return;
}
mLaunchTaskFragments.removeAt(index);
taskFragment.removeImmediately();
@@ -1135,4 +1181,13 @@
mUid = Binder.getCallingUid();
}
}
+
+ void sendTaskFragmentOperationFailure(@NonNull ITaskFragmentOrganizer organizer,
+ @Nullable IBinder errorCallbackToken, @NonNull Throwable exception) {
+ if (organizer == null) {
+ throw new IllegalArgumentException("Not allowed to operate with invalid organizer");
+ }
+ mService.mTaskFragmentOrganizerController
+ .onTaskFragmentError(organizer, errorCallbackToken, exception);
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 7e721be..c9b1506 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -238,6 +238,7 @@
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
+import android.view.InsetsVisibilities;
import android.view.Surface;
import android.view.Surface.Rotation;
import android.view.SurfaceControl;
@@ -748,7 +749,7 @@
private boolean mIsDimming = false;
private @Nullable InsetsSourceProvider mControllableInsetProvider;
- private final InsetsState mRequestedInsetsState = new InsetsState();
+ private final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
/**
* Freeze the insets state in some cases that not necessarily keeps up-to-date to the client.
@@ -871,27 +872,23 @@
*/
@Override
public boolean getRequestedVisibility(@InternalInsetsType int type) {
- return mRequestedInsetsState.getSourceOrDefaultVisibility(type);
+ return mRequestedVisibilities.getVisibility(type);
}
/**
* Returns all the requested visibilities.
*
- * @return an {@link InsetsState} as the requested visibilities.
+ * @return an {@link InsetsVisibilities} as the requested visibilities.
*/
- InsetsState getRequestedState() {
- return mRequestedInsetsState;
+ InsetsVisibilities getRequestedVisibilities() {
+ return mRequestedVisibilities;
}
/**
* @see #getRequestedVisibility(int)
*/
- void updateRequestedVisibility(InsetsState state) {
- for (int i = 0; i < InsetsState.SIZE; i++) {
- final InsetsSource source = state.peekSource(i);
- if (source == null) continue;
- mRequestedInsetsState.addSource(source);
- }
+ void setRequestedVisibilities(InsetsVisibilities visibilities) {
+ mRequestedVisibilities.set(visibilities);
}
/**
@@ -1172,7 +1169,8 @@
if (WindowManager.LayoutParams.isSystemAlertWindowType(mAttrs.type)) {
return TouchOcclusionMode.USE_OPACITY;
}
- if (isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_ALL)) {
+ if (isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_ALL)
+ || mWmService.mAtmService.getTransitionController().inTransition(this)) {
return TouchOcclusionMode.USE_OPACITY;
}
return TouchOcclusionMode.BLOCK_UNTRUSTED;
@@ -4404,9 +4402,9 @@
pw.println(prefix + "mEmbeddedDisplayContents=" + mEmbeddedDisplayContents);
}
if (dumpAll) {
- final String visibilityString = mRequestedInsetsState.toSourceVisibilityString();
+ final String visibilityString = mRequestedVisibilities.toString();
if (!visibilityString.isEmpty()) {
- pw.println(prefix + "Requested visibility: " + visibilityString);
+ pw.println(prefix + "Requested visibilities: " + visibilityString);
}
}
}
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index e3e2708..fdf23d3 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -59,9 +59,7 @@
private static final boolean DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG);
- private static final long BG_PROCESS_PERIOD = DEBUG
- ? TimeUnit.MINUTES.toMillis(1)
- : TimeUnit.DAYS.toMillis(1);
+ private static final long BG_PROCESS_PERIOD = TimeUnit.DAYS.toMillis(1); // every 1 day.
private IProfCollectd mIProfcollect;
private static ProfcollectForwardingService sSelfService;
@@ -286,6 +284,11 @@
updateEngine.bind(new UpdateEngineCallback() {
@Override
public void onStatusUpdate(int status, float percent) {
+ if (DEBUG) {
+ Log.d(LOG_TAG, "Received OTA status update, status: " + status + ", percent: "
+ + percent);
+ }
+
if (status == UpdateEngine.UpdateStatusConstants.UPDATED_NEED_REBOOT) {
packProfileReport();
}
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 a254f68..16afef5 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -3002,7 +3002,8 @@
final PendingIntent pi = getNewMockPendingIntent();
setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i, pi);
- verify(() -> MetricsHelper.pushAlarmScheduled(argThat(a -> a.matches(pi, null))));
+ verify(() -> MetricsHelper.pushAlarmScheduled(argThat(a -> a.matches(pi, null)),
+ anyInt()));
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
index 803a0c1..26b5218 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
@@ -1003,7 +1003,7 @@
dummyPackageName, dummyClassName), "", definingUid));
}
app.mServices.setConnectionGroup(connectionGroup);
- app.mState.setSetProcState(procState);
+ app.mState.setReportedProcState(procState);
app.mProfile.setLastMemInfo(spy(new Debug.MemoryInfo()));
app.mProfile.setLastPss(pss);
app.mProfile.setLastRss(rss);
diff --git a/services/tests/mockingservicestests/src/com/android/server/appsearch/AppSearchConfigTest.java b/services/tests/mockingservicestests/src/com/android/server/appsearch/AppSearchConfigTest.java
index 8336663..9926953 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appsearch/AppSearchConfigTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appsearch/AppSearchConfigTest.java
@@ -50,6 +50,14 @@
AppSearchConfig.DEFAULT_SAMPLING_INTERVAL);
assertThat(appSearchConfig.getCachedSamplingIntervalForPutDocumentStats()).isEqualTo(
AppSearchConfig.DEFAULT_SAMPLING_INTERVAL);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForInitializeStats()).isEqualTo(
+ AppSearchConfig.DEFAULT_SAMPLING_INTERVAL);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForSearchStats()).isEqualTo(
+ AppSearchConfig.DEFAULT_SAMPLING_INTERVAL);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForGlobalSearchStats()).isEqualTo(
+ AppSearchConfig.DEFAULT_SAMPLING_INTERVAL);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForOptimizeStats()).isEqualTo(
+ AppSearchConfig.DEFAULT_SAMPLING_INTERVAL);
assertThat(appSearchConfig.getCachedLimitConfigMaxDocumentSizeBytes()).isEqualTo(
AppSearchConfig.DEFAULT_LIMIT_CONFIG_MAX_DOCUMENT_SIZE_BYTES);
assertThat(appSearchConfig.getCachedLimitConfigMaxDocumentCount()).isEqualTo(
@@ -100,6 +108,11 @@
final int samplingIntervalDefault = -1;
final int samplingIntervalPutDocumentStats = -2;
final int samplingIntervalBatchCallStats = -3;
+ final int samplingIntervalInitializeStats = -4;
+ final int samplingIntervalSearchStats = -5;
+ final int samplingIntervalGlobalSearchStats = -6;
+ final int samplingIntervalOptimizeStats = -7;
+
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
Integer.toString(samplingIntervalDefault),
@@ -112,6 +125,22 @@
AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS,
Integer.toString(samplingIntervalBatchCallStats),
false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_INITIALIZE_STATS,
+ Integer.toString(samplingIntervalInitializeStats),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_SEARCH_STATS,
+ Integer.toString(samplingIntervalSearchStats),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_GLOBAL_SEARCH_STATS,
+ Integer.toString(samplingIntervalGlobalSearchStats),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_OPTIMIZE_STATS,
+ Integer.toString(samplingIntervalOptimizeStats),
+ false);
AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR);
@@ -121,6 +150,14 @@
samplingIntervalPutDocumentStats);
assertThat(appSearchConfig.getCachedSamplingIntervalForBatchCallStats()).isEqualTo(
samplingIntervalBatchCallStats);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForInitializeStats()).isEqualTo(
+ samplingIntervalInitializeStats);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForSearchStats()).isEqualTo(
+ samplingIntervalSearchStats);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForGlobalSearchStats()).isEqualTo(
+ samplingIntervalGlobalSearchStats);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForOptimizeStats()).isEqualTo(
+ samplingIntervalOptimizeStats);
}
@Test
@@ -128,6 +165,10 @@
int samplingIntervalDefault = -1;
int samplingIntervalPutDocumentStats = -2;
int samplingIntervalBatchCallStats = -3;
+ int samplingIntervalInitializeStats = -4;
+ int samplingIntervalSearchStats = -5;
+ int samplingIntervalGlobalSearchStats = -6;
+ int samplingIntervalOptimizeStats = -7;
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
Integer.toString(samplingIntervalDefault),
@@ -140,12 +181,32 @@
AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS,
Integer.toString(samplingIntervalBatchCallStats),
false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_INITIALIZE_STATS,
+ Integer.toString(samplingIntervalInitializeStats),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_SEARCH_STATS,
+ Integer.toString(samplingIntervalSearchStats),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_GLOBAL_SEARCH_STATS,
+ Integer.toString(samplingIntervalGlobalSearchStats),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_OPTIMIZE_STATS,
+ Integer.toString(samplingIntervalOptimizeStats),
+ false);
AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR);
// Overrides
samplingIntervalDefault = -4;
samplingIntervalPutDocumentStats = -5;
samplingIntervalBatchCallStats = -6;
+ samplingIntervalInitializeStats = -7;
+ samplingIntervalSearchStats = -8;
+ samplingIntervalGlobalSearchStats = -9;
+ samplingIntervalOptimizeStats = -10;
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
Integer.toString(samplingIntervalDefault),
@@ -158,6 +219,22 @@
AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS,
Integer.toString(samplingIntervalBatchCallStats),
false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_INITIALIZE_STATS,
+ Integer.toString(samplingIntervalInitializeStats),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_SEARCH_STATS,
+ Integer.toString(samplingIntervalSearchStats),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_GLOBAL_SEARCH_STATS,
+ Integer.toString(samplingIntervalGlobalSearchStats),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_OPTIMIZE_STATS,
+ Integer.toString(samplingIntervalOptimizeStats),
+ false);
assertThat(appSearchConfig.getCachedSamplingIntervalDefault()).isEqualTo(
samplingIntervalDefault);
@@ -165,6 +242,14 @@
samplingIntervalPutDocumentStats);
assertThat(appSearchConfig.getCachedSamplingIntervalForBatchCallStats()).isEqualTo(
samplingIntervalBatchCallStats);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForInitializeStats()).isEqualTo(
+ samplingIntervalInitializeStats);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForSearchStats()).isEqualTo(
+ samplingIntervalSearchStats);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForGlobalSearchStats()).isEqualTo(
+ samplingIntervalGlobalSearchStats);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForOptimizeStats()).isEqualTo(
+ samplingIntervalOptimizeStats);
}
/**
@@ -366,6 +451,18 @@
() -> appSearchConfig.getCachedSamplingIntervalForPutDocumentStats());
Assert.assertThrows("Trying to use a closed AppSearchConfig instance.",
IllegalStateException.class,
+ () -> appSearchConfig.getCachedSamplingIntervalForInitializeStats());
+ Assert.assertThrows("Trying to use a closed AppSearchConfig instance.",
+ IllegalStateException.class,
+ () -> appSearchConfig.getCachedSamplingIntervalForSearchStats());
+ Assert.assertThrows("Trying to use a closed AppSearchConfig instance.",
+ IllegalStateException.class,
+ () -> appSearchConfig.getCachedSamplingIntervalForGlobalSearchStats());
+ Assert.assertThrows("Trying to use a closed AppSearchConfig instance.",
+ IllegalStateException.class,
+ () -> appSearchConfig.getCachedSamplingIntervalForOptimizeStats());
+ Assert.assertThrows("Trying to use a closed AppSearchConfig instance.",
+ IllegalStateException.class,
() -> appSearchConfig.getCachedBytesOptimizeThreshold());
Assert.assertThrows("Trying to use a closed AppSearchConfig instance.",
IllegalStateException.class,
diff --git a/services/tests/mockingservicestests/src/com/android/server/appsearch/OWNERS b/services/tests/mockingservicestests/src/com/android/server/appsearch/OWNERS
new file mode 100644
index 0000000..24f6b0b
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/appsearch/OWNERS
@@ -0,0 +1 @@
+include /apex/appsearch/OWNERS
\ No newline at end of file
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
index f91cb28..521be70 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
@@ -459,6 +459,66 @@
assertThat(apkSession.getErrorMessage()).isEqualTo("Another apex session failed");
}
+ @Test
+ public void getSessionIdByPackageName() throws Exception {
+ FakeStagedSession session = new FakeStagedSession(239);
+ session.setCommitted(true);
+ session.setSessionReady();
+ session.setPackageName("com.foo");
+
+ mStagingManager.createSession(session);
+ assertThat(mStagingManager.getSessionIdByPackageName("com.foo")).isEqualTo(239);
+ }
+
+ @Test
+ public void getSessionIdByPackageName_appliedSession_ignores() throws Exception {
+ FakeStagedSession session = new FakeStagedSession(37);
+ session.setCommitted(true);
+ session.setSessionApplied();
+ session.setPackageName("com.foo");
+
+ mStagingManager.createSession(session);
+ assertThat(mStagingManager.getSessionIdByPackageName("com.foo")).isEqualTo(-1);
+ }
+
+ @Test
+ public void getSessionIdByPackageName_failedSession_ignores() throws Exception {
+ FakeStagedSession session = new FakeStagedSession(73);
+ session.setCommitted(true);
+ session.setSessionFailed(1, "whatevs");
+ session.setPackageName("com.foo");
+
+ mStagingManager.createSession(session);
+ assertThat(mStagingManager.getSessionIdByPackageName("com.foo")).isEqualTo(-1);
+ }
+
+ @Test
+ public void getSessionIdByPackageName_destroyedSession_ignores() throws Exception {
+ FakeStagedSession session = new FakeStagedSession(23);
+ session.setCommitted(true);
+ session.setDestroyed(true);
+ session.setPackageName("com.foo");
+
+ mStagingManager.createSession(session);
+ assertThat(mStagingManager.getSessionIdByPackageName("com.foo")).isEqualTo(-1);
+ }
+
+ @Test
+ public void getSessionIdByPackageName_noSessions() throws Exception {
+ assertThat(mStagingManager.getSessionIdByPackageName("com.foo")).isEqualTo(-1);
+ }
+
+ @Test
+ public void getSessionIdByPackageName_noSessionHasThisPackage() throws Exception {
+ FakeStagedSession session = new FakeStagedSession(37);
+ session.setCommitted(true);
+ session.setSessionApplied();
+ session.setPackageName("com.foo");
+
+ mStagingManager.createSession(session);
+ assertThat(mStagingManager.getSessionIdByPackageName("com.bar")).isEqualTo(-1);
+ }
+
private StagingManager.StagedSession createSession(int sessionId, String packageName,
long committedMillis) {
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
index 5b067bc..f40a5ad 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
@@ -42,6 +42,7 @@
import com.android.server.appsearch.external.localstorage.converter.GenericDocumentToProtoConverter;
import com.android.server.appsearch.external.localstorage.stats.InitializeStats;
+import com.android.server.appsearch.external.localstorage.stats.OptimizeStats;
import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
import com.android.server.appsearch.icing.proto.DocumentProto;
import com.android.server.appsearch.icing.proto.GetOptimizeInfoResultProto;
@@ -451,19 +452,26 @@
assertThat(optimizeInfo.getOptimizableDocs()).isEqualTo(1);
// Increase mutation counter and stop before reach the threshold
- mAppSearchImpl.checkForOptimize(AppSearchImpl.CHECK_OPTIMIZE_INTERVAL - 1);
+ mAppSearchImpl.checkForOptimize(
+ AppSearchImpl.CHECK_OPTIMIZE_INTERVAL - 1, /*builder=*/ null);
// Verify the optimize() isn't triggered.
optimizeInfo = mAppSearchImpl.getOptimizeInfoResultLocked();
assertThat(optimizeInfo.getOptimizableDocs()).isEqualTo(1);
// Increase the counter and reach the threshold, optimize() should be triggered.
- mAppSearchImpl.checkForOptimize(/*mutateBatchSize=*/ 1);
+ OptimizeStats.Builder builder = new OptimizeStats.Builder();
+ mAppSearchImpl.checkForOptimize(/*mutateBatchSize=*/ 1, builder);
// Verify optimize() is triggered.
optimizeInfo = mAppSearchImpl.getOptimizeInfoResultLocked();
assertThat(optimizeInfo.getOptimizableDocs()).isEqualTo(0);
assertThat(optimizeInfo.getEstimatedOptimizableBytes()).isEqualTo(0);
+
+ // Verify the stats have been set.
+ OptimizeStats oStats = builder.build();
+ assertThat(oStats.getOriginalDocumentCount()).isEqualTo(1);
+ assertThat(oStats.getDeletedDocumentCount()).isEqualTo(1);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
index 7bacbb6..7c97687 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
@@ -29,12 +29,14 @@
import com.android.server.appsearch.external.localstorage.stats.CallStats;
import com.android.server.appsearch.external.localstorage.stats.InitializeStats;
+import com.android.server.appsearch.external.localstorage.stats.OptimizeStats;
import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
import com.android.server.appsearch.external.localstorage.stats.SearchStats;
import com.android.server.appsearch.icing.proto.DeleteStatsProto;
import com.android.server.appsearch.icing.proto.DocumentProto;
import com.android.server.appsearch.icing.proto.InitializeStatsProto;
+import com.android.server.appsearch.icing.proto.OptimizeStatsProto;
import com.android.server.appsearch.icing.proto.PutDocumentStatsProto;
import com.android.server.appsearch.icing.proto.PutResultProto;
import com.android.server.appsearch.icing.proto.QueryStatsProto;
@@ -81,6 +83,7 @@
@Nullable InitializeStats mInitializeStats;
@Nullable SearchStats mSearchStats;
@Nullable RemoveStats mRemoveStats;
+ @Nullable OptimizeStats mOptimizeStats;
@Override
public void logStats(@NonNull CallStats stats) {
@@ -106,6 +109,11 @@
public void logStats(@NonNull RemoveStats stats) {
mRemoveStats = stats;
}
+
+ @Override
+ public void logStats(@NonNull OptimizeStats stats) {
+ mOptimizeStats = stats;
+ }
}
@Test
@@ -286,6 +294,48 @@
assertThat(rStats.getDeletedDocumentCount()).isEqualTo(nativeNumDocumentDeleted);
}
+ @Test
+ public void testAppSearchLoggerHelper_testCopyNativeStats_optimize() {
+ int nativeLatencyMillis = 1;
+ int nativeDocumentStoreOptimizeLatencyMillis = 2;
+ int nativeIndexRestorationLatencyMillis = 3;
+ int nativeNumOriginalDocuments = 4;
+ int nativeNumDeletedDocuments = 5;
+ int nativeNumExpiredDocuments = 6;
+ long nativeStorageSizeBeforeBytes = Integer.MAX_VALUE + 1;
+ long nativeStorageSizeAfterBytes = Integer.MAX_VALUE + 2;
+ long nativeTimeSinceLastOptimizeMillis = Integer.MAX_VALUE + 3;
+ OptimizeStatsProto optimizeStatsProto =
+ OptimizeStatsProto.newBuilder()
+ .setLatencyMs(nativeLatencyMillis)
+ .setDocumentStoreOptimizeLatencyMs(nativeDocumentStoreOptimizeLatencyMillis)
+ .setIndexRestorationLatencyMs(nativeIndexRestorationLatencyMillis)
+ .setNumOriginalDocuments(nativeNumOriginalDocuments)
+ .setNumDeletedDocuments(nativeNumDeletedDocuments)
+ .setNumExpiredDocuments(nativeNumExpiredDocuments)
+ .setStorageSizeBefore(nativeStorageSizeBeforeBytes)
+ .setStorageSizeAfter(nativeStorageSizeAfterBytes)
+ .setTimeSinceLastOptimizeMs(nativeTimeSinceLastOptimizeMillis)
+ .build();
+ OptimizeStats.Builder oBuilder = new OptimizeStats.Builder();
+
+ AppSearchLoggerHelper.copyNativeStats(optimizeStatsProto, oBuilder);
+
+ OptimizeStats oStats = oBuilder.build();
+ assertThat(oStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
+ assertThat(oStats.getDocumentStoreOptimizeLatencyMillis())
+ .isEqualTo(nativeDocumentStoreOptimizeLatencyMillis);
+ assertThat(oStats.getIndexRestorationLatencyMillis())
+ .isEqualTo(nativeIndexRestorationLatencyMillis);
+ assertThat(oStats.getOriginalDocumentCount()).isEqualTo(nativeNumOriginalDocuments);
+ assertThat(oStats.getDeletedDocumentCount()).isEqualTo(nativeNumDeletedDocuments);
+ assertThat(oStats.getExpiredDocumentCount()).isEqualTo(nativeNumExpiredDocuments);
+ assertThat(oStats.getStorageSizeBeforeBytes()).isEqualTo(nativeStorageSizeBeforeBytes);
+ assertThat(oStats.getStorageSizeAfterBytes()).isEqualTo(nativeStorageSizeAfterBytes);
+ assertThat(oStats.getTimeSinceLastOptimizeMillis())
+ .isEqualTo(nativeTimeSinceLastOptimizeMillis);
+ }
+
//
// Testing actual logging
//
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
index 57d9941..c1dc0e4 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
@@ -348,4 +348,49 @@
assertThat(rStats.getDeleteType()).isEqualTo(deleteType);
assertThat(rStats.getDeletedDocumentCount()).isEqualTo(documentDeletedCount);
}
+
+ @Test
+ public void testAppSearchStats_OptimizeStats() {
+ int nativeLatencyMillis = 1;
+ int nativeDocumentStoreOptimizeLatencyMillis = 2;
+ int nativeIndexRestorationLatencyMillis = 3;
+ int nativeNumOriginalDocuments = 4;
+ int nativeNumDeletedDocuments = 5;
+ int nativeNumExpiredDocuments = 6;
+ long nativeStorageSizeBeforeBytes = Integer.MAX_VALUE + 1;
+ long nativeStorageSizeAfterBytes = Integer.MAX_VALUE + 2;
+ long nativeTimeSinceLastOptimizeMillis = Integer.MAX_VALUE + 3;
+
+ final OptimizeStats oStats =
+ new OptimizeStats.Builder()
+ .setStatusCode(TEST_STATUS_CODE)
+ .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS)
+ .setNativeLatencyMillis(nativeLatencyMillis)
+ .setDocumentStoreOptimizeLatencyMillis(
+ nativeDocumentStoreOptimizeLatencyMillis)
+ .setIndexRestorationLatencyMillis(nativeIndexRestorationLatencyMillis)
+ .setOriginalDocumentCount(nativeNumOriginalDocuments)
+ .setDeletedDocumentCount(nativeNumDeletedDocuments)
+ .setExpiredDocumentCount(nativeNumExpiredDocuments)
+ .setStorageSizeBeforeBytes(nativeStorageSizeBeforeBytes)
+ .setStorageSizeAfterBytes(nativeStorageSizeAfterBytes)
+ .setTimeSinceLastOptimizeMillis(nativeTimeSinceLastOptimizeMillis)
+ .build();
+
+ assertThat(oStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE);
+ assertThat(oStats.getTotalLatencyMillis()).isEqualTo(TEST_TOTAL_LATENCY_MILLIS);
+ assertThat(oStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
+ assertThat(oStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
+ assertThat(oStats.getDocumentStoreOptimizeLatencyMillis())
+ .isEqualTo(nativeDocumentStoreOptimizeLatencyMillis);
+ assertThat(oStats.getIndexRestorationLatencyMillis())
+ .isEqualTo(nativeIndexRestorationLatencyMillis);
+ assertThat(oStats.getOriginalDocumentCount()).isEqualTo(nativeNumOriginalDocuments);
+ assertThat(oStats.getDeletedDocumentCount()).isEqualTo(nativeNumDeletedDocuments);
+ assertThat(oStats.getExpiredDocumentCount()).isEqualTo(nativeNumExpiredDocuments);
+ assertThat(oStats.getStorageSizeBeforeBytes()).isEqualTo(nativeStorageSizeBeforeBytes);
+ assertThat(oStats.getStorageSizeAfterBytes()).isEqualTo(nativeStorageSizeAfterBytes);
+ assertThat(oStats.getTimeSinceLastOptimizeMillis())
+ .isEqualTo(nativeTimeSinceLastOptimizeMillis);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index 1fe4123..8592166a 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -360,7 +360,8 @@
false /* restricted */, TAG, 1 /* cookie */, false /* requireConfirmation */,
TEST_SENSOR_ID, true /* isStrongBiometric */, 0 /* statsModality */,
0 /* statsClient */, null /* taskStackListener */, mock(LockoutTracker.class),
- false /* isKeyguard */, true /* shouldVibrate */);
+ false /* isKeyguard */, true /* shouldVibrate */,
+ false /* isKeyguardBypassEnabled */);
}
@Override
@@ -388,7 +389,8 @@
false /* restricted */, TAG, 1 /* cookie */, false /* requireConfirmation */,
TEST_SENSOR_ID, true /* isStrongBiometric */, 0 /* statsModality */,
0 /* statsClient */, null /* taskStackListener */, mock(LockoutTracker.class),
- false /* isKeyguard */, true /* shouldVibrate */);
+ false /* isKeyguard */, true /* shouldVibrate */,
+ false /* isKeyguardBypassEnabled */);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
index fb05825..f1adcae 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
@@ -17,6 +17,7 @@
package com.android.server.biometrics.sensors;
import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_FACE;
+import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_FP_OTHER;
import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_UDFPS;
import static junit.framework.Assert.assertEquals;
@@ -259,6 +260,117 @@
}
@Test
+ public void testKeyguard_faceRejectedWhenUdfpsTouching_thenUdfpsRejected() {
+ mCoexCoordinator.reset();
+
+ AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
+ when(faceClient.isKeyguard()).thenReturn(true);
+ when(faceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+
+ AuthenticationClient<?> udfpsClient = mock(AuthenticationClient.class,
+ withSettings().extraInterfaces(Udfps.class));
+ when(udfpsClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+ when(udfpsClient.isKeyguard()).thenReturn(true);
+ when(((Udfps) udfpsClient).isPointerDown()).thenReturn(true);
+
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, udfpsClient);
+
+ mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, faceClient,
+ LockoutTracker.LOCKOUT_NONE, mCallback);
+ verify(mCallback, never()).sendHapticFeedback();
+ verify(mCallback).handleLifecycleAfterAuth();
+
+ // BiometricScheduler removes the face authentication client after rejection
+ mCoexCoordinator.removeAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
+
+ // Then UDFPS rejected
+ CoexCoordinator.Callback udfpsCallback = mock(CoexCoordinator.Callback.class);
+ mCoexCoordinator.onAuthenticationRejected(1 /* currentTimeMillis */, udfpsClient,
+ LockoutTracker.LOCKOUT_NONE, udfpsCallback);
+ verify(udfpsCallback).sendHapticFeedback();
+ verify(udfpsCallback).sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */);
+ verify(mCallback, never()).sendHapticFeedback();
+ }
+
+ @Test
+ public void testKeyguard_udfpsRejected_thenFaceRejected() {
+ mCoexCoordinator.reset();
+
+ AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
+ when(faceClient.isKeyguard()).thenReturn(true);
+ when(faceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+
+ AuthenticationClient<?> udfpsClient = mock(AuthenticationClient.class,
+ withSettings().extraInterfaces(Udfps.class));
+ when(udfpsClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+ when(udfpsClient.isKeyguard()).thenReturn(true);
+ when(((Udfps) udfpsClient).isPointerDown()).thenReturn(true);
+
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, udfpsClient);
+
+ mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, udfpsClient,
+ LockoutTracker.LOCKOUT_NONE, mCallback);
+ // Client becomes paused, but finger does not necessarily lift, since we suppress the haptic
+ when(udfpsClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED_PAUSED);
+ verify(mCallback, never()).sendHapticFeedback();
+ verify(mCallback).handleLifecycleAfterAuth();
+
+ // Then face rejected. Note that scheduler leaves UDFPS in the CoexCoordinator since
+ // unlike face, its lifecycle becomes "paused" instead of "finished".
+ CoexCoordinator.Callback faceCallback = mock(CoexCoordinator.Callback.class);
+ mCoexCoordinator.onAuthenticationRejected(1 /* currentTimeMillis */, faceClient,
+ LockoutTracker.LOCKOUT_NONE, faceCallback);
+ verify(faceCallback).sendHapticFeedback();
+ verify(faceCallback).sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */);
+ verify(mCallback, never()).sendHapticFeedback();
+ }
+
+ @Test
+ public void testKeyguard_capacitiveAccepted_whenFaceScanning() {
+ mCoexCoordinator.reset();
+
+ AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
+ when(faceClient.isKeyguard()).thenReturn(true);
+ when(faceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+
+ AuthenticationClient<?> fpClient = mock(AuthenticationClient.class);
+ when(fpClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+ when(fpClient.isKeyguard()).thenReturn(true);
+
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FP_OTHER, fpClient);
+
+ mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, fpClient, mCallback);
+ verify(mCallback).sendHapticFeedback();
+ verify(mCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */);
+ verify(mCallback).handleLifecycleAfterAuth();
+ }
+
+ @Test
+ public void testKeyguard_capacitiveRejected_whenFaceScanning() {
+ mCoexCoordinator.reset();
+
+ AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
+ when(faceClient.isKeyguard()).thenReturn(true);
+ when(faceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+
+ AuthenticationClient<?> fpClient = mock(AuthenticationClient.class);
+ when(fpClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+ when(fpClient.isKeyguard()).thenReturn(true);
+
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FP_OTHER, fpClient);
+
+ mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, fpClient,
+ LockoutTracker.LOCKOUT_NONE, mCallback);
+ verify(mCallback).sendHapticFeedback();
+ verify(mCallback).sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */);
+ verify(mCallback).handleLifecycleAfterAuth();
+ }
+
+ @Test
public void testNonKeyguard_rejectAndNotLockedOut() {
mCoexCoordinator.reset();
diff --git a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
index 1ad8850..cc3591c8 100644
--- a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
@@ -92,7 +92,6 @@
@Mock IThermalService mThermalServiceMock;
@Mock Injector mInjectorMock;
- @Mock BrightnessSetting mBrightnessSetting;
@Captor ArgumentCaptor<IThermalEventListener> mThermalEventListenerCaptor;
@@ -123,7 +122,7 @@
initHandler(null);
final HighBrightnessModeController hbmc = new HighBrightnessModeController(
mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken, DEFAULT_MIN,
- DEFAULT_MAX, null, () -> {}, mContextSpy, mBrightnessSetting);
+ DEFAULT_MAX, null, () -> {}, mContextSpy);
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
}
@@ -132,7 +131,7 @@
initHandler(null);
final HighBrightnessModeController hbmc = new HighBrightnessModeController(
mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken, DEFAULT_MIN,
- DEFAULT_MAX, null, () -> {}, mContextSpy, mBrightnessSetting);
+ DEFAULT_MAX, null, () -> {}, mContextSpy);
hbmc.setAutoBrightnessEnabled(true);
hbmc.onAmbientLuxChange(MINIMUM_LUX - 1); // below allowed range
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
@@ -464,7 +463,7 @@
initHandler(clock);
return new HighBrightnessModeController(mInjectorMock, mHandler, DISPLAY_WIDTH,
DISPLAY_HEIGHT, mDisplayToken, DEFAULT_MIN, DEFAULT_MAX, DEFAULT_HBM_DATA, () -> {},
- mContextSpy, mBrightnessSetting);
+ mContextSpy);
}
private void initHandler(OffsettableClock clock) {
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
index 9044b27..5eb21a5 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -19,6 +19,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.testng.Assert.expectThrows;
import android.platform.test.annotations.Presubmit;
import android.util.ArrayMap;
@@ -200,6 +201,46 @@
assertThat(mSysConfig.getWhitelistedStagedInstallers())
.containsExactly("com.android.package1");
+ assertThat(mSysConfig.getModulesInstallerPackageName()).isNull();
+ }
+
+ @Test
+ public void readPermissions_parsesStagedInstallerWhitelist_modulesInstaller()
+ throws IOException {
+ final String contents =
+ "<config>\n"
+ + " <whitelisted-staged-installer package=\"com.android.package1\" "
+ + " isModulesInstaller=\"true\" />\n"
+ + "</config>";
+ final File folder = createTempSubfolder("folder");
+ createTempFile(folder, "staged-installer-whitelist.xml", contents);
+
+ mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0);
+
+ assertThat(mSysConfig.getWhitelistedStagedInstallers())
+ .containsExactly("com.android.package1");
+ assertThat(mSysConfig.getModulesInstallerPackageName())
+ .isEqualTo("com.android.package1");
+ }
+
+ @Test
+ public void readPermissions_parsesStagedInstallerWhitelist_multipleModulesInstallers()
+ throws IOException {
+ final String contents =
+ "<config>\n"
+ + " <whitelisted-staged-installer package=\"com.android.package1\" "
+ + " isModulesInstaller=\"true\" />\n"
+ + " <whitelisted-staged-installer package=\"com.android.package2\" "
+ + " isModulesInstaller=\"true\" />\n"
+ + "</config>";
+ final File folder = createTempSubfolder("folder");
+ createTempFile(folder, "staged-installer-whitelist.xml", contents);
+
+ IllegalStateException e = expectThrows(
+ IllegalStateException.class,
+ () -> mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0));
+
+ assertThat(e).hasMessageThat().contains("Multiple modules installers");
}
/**
@@ -230,14 +271,16 @@
throws IOException {
final String contents =
"<config>\n"
- + " <allowed-vendor-apex package=\"com.android.apex1\" />\n"
+ + " <allowed-vendor-apex package=\"com.android.apex1\" "
+ + "installerPackage=\"com.installer\" />\n"
+ "</config>";
final File folder = createTempSubfolder("folder");
createTempFile(folder, "vendor-apex-allowlist.xml", contents);
mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0);
- assertThat(mSysConfig.getAllowedVendorApexes()).containsExactly("com.android.apex1");
+ assertThat(mSysConfig.getAllowedVendorApexes())
+ .containsExactly("com.android.apex1", "com.installer");
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 645fa63..9e46e1f 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -93,6 +93,7 @@
import android.view.Display;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -103,7 +104,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -502,6 +502,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testBoundWidgetPackageExempt() throws Exception {
assumeTrue(mInjector.getContext().getSystemService(AppWidgetManager.class) != null);
assertEquals(STANDBY_BUCKET_ACTIVE,
@@ -584,6 +585,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testIsAppIdle_Charging() throws Exception {
TestParoleListener paroleListener = new TestParoleListener();
mController.addListener(paroleListener);
@@ -616,6 +618,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testIsAppIdle_Enabled() throws Exception {
setChargingState(mController, false);
TestParoleListener paroleListener = new TestParoleListener();
@@ -715,6 +718,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testBuckets() throws Exception {
assertTimeout(mController, 0, STANDBY_BUCKET_NEVER);
@@ -747,6 +751,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testSetAppStandbyBucket() throws Exception {
// For a known package, standby bucket should be set properly
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
@@ -766,6 +771,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testAppStandbyBucketOnInstallAndUninstall() throws Exception {
// On package install, standby bucket should be ACTIVE
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_UNKNOWN);
@@ -784,6 +790,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testScreenTimeAndBuckets() throws Exception {
mInjector.setDisplayOn(false);
@@ -807,6 +814,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testForcedIdle() throws Exception {
mController.forceIdleState(PACKAGE_1, USER_ID, true);
assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
@@ -819,6 +827,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testNotificationEvent() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
@@ -832,6 +841,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testSlicePinnedEvent() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
@@ -845,6 +855,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testSlicePinnedPrivEvent() throws Exception {
mController.forceIdleState(PACKAGE_1, USER_ID, true);
reportEvent(mController, SLICE_PINNED_PRIV, mInjector.mElapsedRealtime, PACKAGE_1);
@@ -852,6 +863,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testPredictionTimedOut() throws Exception {
// Set it to timeout or usage, so that prediction can override it
mInjector.mElapsedRealtime = HOUR_MS;
@@ -882,6 +894,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testOverrides() throws Exception {
// Can force to NEVER
mInjector.mElapsedRealtime = HOUR_MS;
@@ -992,6 +1005,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testTimeout() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
@@ -1015,6 +1029,7 @@
/** Test that timeouts still work properly even if invalid configuration values are set. */
@Test
+ @FlakyTest(bugId = 185169504)
public void testTimeout_InvalidThresholds() throws Exception {
mInjector.mSettingsBuilder
.setLong("screen_threshold_active", -1)
@@ -1052,6 +1067,7 @@
* timeout has passed.
*/
@Test
+ @FlakyTest(bugId = 185169504)
public void testTimeoutBeforeRestricted() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
@@ -1078,6 +1094,7 @@
* Test that an app is put into the RESTRICTED bucket after enough time has passed.
*/
@Test
+ @FlakyTest(bugId = 185169504)
public void testRestrictedDelay() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
@@ -1100,6 +1117,7 @@
* Test that an app is put into the RESTRICTED bucket after enough time has passed.
*/
@Test
+ @FlakyTest(bugId = 185169504)
public void testRestrictedDelay_DelayChange() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
@@ -1124,6 +1142,7 @@
* a low bucket after the RESTRICTED timeout.
*/
@Test
+ @FlakyTest(bugId = 185169504)
public void testRestrictedTimeoutOverridesRestoredLowBucketPrediction() throws Exception {
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
@@ -1160,6 +1179,7 @@
* a low bucket after the RESTRICTED timeout.
*/
@Test
+ @FlakyTest(bugId = 185169504)
public void testRestrictedTimeoutOverridesPredictionLowBucket() throws Exception {
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
@@ -1187,6 +1207,7 @@
* interaction.
*/
@Test
+ @FlakyTest(bugId = 185169504)
public void testSystemInteractionOverridesRestrictedTimeout() throws Exception {
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
@@ -1213,6 +1234,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testRestrictedBucketDisabled() throws Exception {
mInjector.mIsRestrictedBucketEnabled = false;
// Get the controller to read the new value. Capturing the ContentObserver isn't possible
@@ -1238,6 +1260,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testRestrictedBucket_EnabledToDisabled() throws Exception {
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD;
@@ -1255,6 +1278,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testPredictionRaiseFromRestrictedTimeout_highBucket() throws Exception {
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
@@ -1272,6 +1296,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testPredictionRaiseFromRestrictedTimeout_lowBucket() throws Exception {
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
@@ -1289,6 +1314,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testCascadingTimeouts() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
@@ -1312,6 +1338,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testOverlappingTimeouts() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
@@ -1343,6 +1370,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testSystemInteractionTimeout() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
// Fast forward to RARE
@@ -1366,6 +1394,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testInitialForegroundServiceTimeout() throws Exception {
mInjector.mElapsedRealtime = 1 * RARE_THRESHOLD + 100;
// Make sure app is in NEVER bucket
@@ -1399,6 +1428,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testPredictionNotOverridden() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
@@ -1424,8 +1454,8 @@
assertBucket(STANDBY_BUCKET_ACTIVE);
}
- @Ignore
@Test
+ @FlakyTest(bugId = 185169504)
public void testPredictionStrikesBack() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
@@ -1451,6 +1481,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testSystemForcedFlags_NotAddedForUserForce() throws Exception {
final int expectedReason = REASON_MAIN_FORCED_BY_USER;
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
@@ -1465,6 +1496,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testSystemForcedFlags_AddedForSystemForce() throws Exception {
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
REASON_MAIN_DEFAULT);
@@ -1487,6 +1519,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testSystemForcedFlags_SystemForceChangesBuckets() throws Exception {
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
REASON_MAIN_DEFAULT);
@@ -1524,6 +1557,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testRestrictApp_MainReason() throws Exception {
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
REASON_MAIN_DEFAULT);
@@ -1598,6 +1632,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testUserInteraction_CrossProfile() throws Exception {
mInjector.mRunningUsers = new int[] {USER_ID, USER_ID2, USER_ID3};
mInjector.mCrossProfileTargets = Arrays.asList(USER_HANDLE_USER2);
@@ -1621,6 +1656,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testUnexemptedSyncScheduled() throws Exception {
rearmLatch(PACKAGE_1);
mController.addListener(mListener);
@@ -1642,6 +1678,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testExemptedSyncScheduled() throws Exception {
setAndAssertBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_MAIN_FORCED_BY_SYSTEM);
mInjector.mDeviceIdleMode = true;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index e367579..488875b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1854,7 +1854,7 @@
doReturn(WindowManagerGlobal.ADD_STARTING_NOT_NEEDED).when(session).addToDisplay(
any() /* window */, any() /* attrs */,
anyInt() /* viewVisibility */, anyInt() /* displayId */,
- any() /* requestedVisibility */, any() /* outInputChannel */,
+ any() /* requestedVisibilities */, any() /* outInputChannel */,
any() /* outInsetsState */, any() /* outActiveControls */);
mAtm.mWindowManager.mStartingSurfaceController
.createTaskSnapshotSurface(activity, snapshot);
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 a0b5fed..1191035 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -42,6 +42,7 @@
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -120,6 +121,7 @@
import android.view.ISystemGestureExclusionListener;
import android.view.IWindowManager;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -870,19 +872,6 @@
.setDisplayInfoOverrideFromWindowManager(dc.getDisplayId(), null);
}
- @UseTestDisplay
- @Test
- public void testClearLastFocusWhenReparentingFocusedWindow() {
- final DisplayContent defaultDisplay = mWm.getDefaultDisplayContentLocked();
- final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
- defaultDisplay, "window");
- defaultDisplay.mLastFocus = window;
- mDisplayContent.mCurrentFocus = window;
- mDisplayContent.reParentWindowToken(window.mToken);
-
- assertNull(defaultDisplay.mLastFocus);
- }
-
@Test
public void testGetPreferredOptionsPanelGravityFromDifferentDisplays() {
final DisplayContent portraitDisplay = createNewDisplay();
@@ -1217,10 +1206,10 @@
win.getAttrs().layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
win.getAttrs().privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION;
win.getAttrs().insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
- final InsetsState requestedState = new InsetsState();
- requestedState.getSource(ITYPE_NAVIGATION_BAR).setVisible(false);
- requestedState.getSource(ITYPE_STATUS_BAR).setVisible(false);
- win.updateRequestedVisibility(requestedState);
+ final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+ requestedVisibilities.setVisibility(ITYPE_NAVIGATION_BAR, false);
+ requestedVisibilities.setVisibility(ITYPE_STATUS_BAR, false);
+ win.setRequestedVisibilities(requestedVisibilities);
win.mActivityRecord.mTargetSdk = P;
performLayout(dc);
@@ -1748,6 +1737,31 @@
}
@Test
+ public void testFindScrollCaptureTargetWindow_secure() {
+ DisplayContent display = createNewDisplay();
+ Task rootTask = createTask(display);
+ Task task = createTaskInRootTask(rootTask, 0 /* userId */);
+ WindowState secureWindow = createWindow(null, TYPE_APPLICATION, "Secure Window");
+ secureWindow.mAttrs.flags |= FLAG_SECURE;
+
+ WindowState result = display.findScrollCaptureTargetWindow(null,
+ ActivityTaskManager.INVALID_TASK_ID);
+ assertNull(result);
+ }
+
+ @Test
+ public void testFindScrollCaptureTargetWindow_secureTaskId() {
+ DisplayContent display = createNewDisplay();
+ Task rootTask = createTask(display);
+ Task task = createTaskInRootTask(rootTask, 0 /* userId */);
+ WindowState secureWindow = createWindow(null, TYPE_APPLICATION, "Secure Window");
+ secureWindow.mAttrs.flags |= FLAG_SECURE;
+
+ WindowState result = display.findScrollCaptureTargetWindow(null, task.mTaskId);
+ assertNull(result);
+ }
+
+ @Test
public void testFindScrollCaptureTargetWindow_taskId() {
DisplayContent display = createNewDisplay();
Task rootTask = createTask(display);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 3741d49..3c7c4fd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -65,6 +65,7 @@
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.PrivacyIndicatorBounds;
import android.view.RoundedCorners;
import android.view.WindowInsets.Side;
@@ -478,9 +479,9 @@
mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
mDisplayContent.getInsetsStateController().getRawInsetsState()
.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
- final InsetsState requestedState = new InsetsState();
- requestedState.getSource(ITYPE_STATUS_BAR).setVisible(false);
- mWindow.updateRequestedVisibility(requestedState);
+ final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+ requestedVisibilities.setVisibility(ITYPE_STATUS_BAR, false);
+ mWindow.setRequestedVisibilities(requestedVisibilities);
addWindowWithRawInsetsState(mWindow);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -498,9 +499,9 @@
mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
mDisplayContent.getInsetsStateController().getRawInsetsState()
.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
- final InsetsState requestedState = new InsetsState();
- requestedState.getSource(ITYPE_STATUS_BAR).setVisible(false);
- mWindow.updateRequestedVisibility(requestedState);
+ final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+ requestedVisibilities.setVisibility(ITYPE_STATUS_BAR, false);
+ mWindow.setRequestedVisibilities(requestedVisibilities);
mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
addWindowWithRawInsetsState(mWindow);
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index 5b04c91..07d467b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -49,6 +49,7 @@
import android.view.InsetsSource;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import androidx.test.filters.SmallTest;
@@ -181,9 +182,9 @@
// Add a fullscreen (MATCH_PARENT x MATCH_PARENT) app window which hides status bar.
final WindowState fullscreenApp = addWindow(TYPE_APPLICATION, "fullscreenApp");
- final InsetsState requestedState = new InsetsState();
- requestedState.getSource(ITYPE_STATUS_BAR).setVisible(false);
- fullscreenApp.updateRequestedVisibility(requestedState);
+ final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+ requestedVisibilities.setVisibility(ITYPE_STATUS_BAR, false);
+ fullscreenApp.setRequestedVisibilities(requestedVisibilities);
// Add a non-fullscreen dialog window.
final WindowState dialog = addWindow(TYPE_APPLICATION, "dialog");
@@ -216,9 +217,9 @@
// Assume mFocusedWindow is updated but mTopFullscreenOpaqueWindowState hasn't.
final WindowState newFocusedFullscreenApp = addWindow(TYPE_APPLICATION, "newFullscreenApp");
- final InsetsState newRequestedState = new InsetsState();
- newRequestedState.getSource(ITYPE_STATUS_BAR).setVisible(true);
- newFocusedFullscreenApp.updateRequestedVisibility(newRequestedState);
+ final InsetsVisibilities newRequestedVisibilities = new InsetsVisibilities();
+ newRequestedVisibilities.setVisibility(ITYPE_STATUS_BAR, true);
+ newFocusedFullscreenApp.setRequestedVisibilities(newRequestedVisibilities);
// Make sure status bar is hidden by previous insets state.
mDisplayContent.getInsetsPolicy().updateBarControlTarget(fullscreenApp);
@@ -279,10 +280,10 @@
doNothing().when(policy).startAnimation(anyBoolean(), any());
// Make both system bars invisible.
- final InsetsState requestedState = new InsetsState();
- requestedState.getSource(ITYPE_STATUS_BAR).setVisible(false);
- requestedState.getSource(ITYPE_NAVIGATION_BAR).setVisible(false);
- mAppWindow.updateRequestedVisibility(requestedState);
+ final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+ requestedVisibilities.setVisibility(ITYPE_STATUS_BAR, false);
+ requestedVisibilities.setVisibility(ITYPE_NAVIGATION_BAR, false);
+ mAppWindow.setRequestedVisibilities(requestedVisibilities);
policy.updateBarControlTarget(mAppWindow);
waitUntilWindowAnimatorIdle();
assertFalse(mDisplayContent.getInsetsStateController().getRawInsetsState()
@@ -373,7 +374,10 @@
assertTrue(state.getSource(ITYPE_STATUS_BAR).isVisible());
assertTrue(state.getSource(ITYPE_NAVIGATION_BAR).isVisible());
- mAppWindow.updateRequestedVisibility(state);
+ final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+ requestedVisibilities.setVisibility(ITYPE_STATUS_BAR, true);
+ requestedVisibilities.setVisibility(ITYPE_NAVIGATION_BAR, true);
+ mAppWindow.setRequestedVisibilities(requestedVisibilities);
policy.onInsetsModified(mAppWindow);
waitUntilWindowAnimatorIdle();
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
index c483ae9..2987f94 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
@@ -31,7 +31,7 @@
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.InsetsSource;
-import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import androidx.test.filters.SmallTest;
@@ -203,9 +203,9 @@
statusBar.getFrame().set(0, 0, 500, 100);
mProvider.setWindow(statusBar, null, null);
mProvider.updateControlForTarget(target, false /* force */);
- InsetsState state = new InsetsState();
- state.getSource(ITYPE_STATUS_BAR).setVisible(false);
- target.updateRequestedVisibility(state);
+ final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+ requestedVisibilities.setVisibility(ITYPE_STATUS_BAR, false);
+ target.setRequestedVisibilities(requestedVisibilities);
mProvider.updateClientVisibility(target);
assertFalse(mSource.isVisible());
}
@@ -216,9 +216,9 @@
final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
statusBar.getFrame().set(0, 0, 500, 100);
mProvider.setWindow(statusBar, null, null);
- InsetsState state = new InsetsState();
- state.getSource(ITYPE_STATUS_BAR).setVisible(false);
- target.updateRequestedVisibility(state);
+ final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+ requestedVisibilities.setVisibility(ITYPE_STATUS_BAR, false);
+ target.setRequestedVisibilities(requestedVisibilities);
mProvider.updateClientVisibility(target);
assertTrue(mSource.isVisible());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index 80961d7..f8c84df 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -48,6 +48,7 @@
import android.platform.test.annotations.Presubmit;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import androidx.test.filters.SmallTest;
@@ -174,10 +175,10 @@
mImeWindow.setHasSurface(true);
getController().getSourceProvider(ITYPE_IME).setWindow(mImeWindow, null, null);
getController().onImeControlTargetChanged(mDisplayContent.getImeTarget(IME_TARGET_INPUT));
- final InsetsState requestedState = new InsetsState();
- requestedState.getSource(ITYPE_IME).setVisible(true);
+ final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+ requestedVisibilities.setVisibility(ITYPE_IME, true);
mDisplayContent.getImeTarget(IME_TARGET_INPUT).getWindow()
- .updateRequestedVisibility(requestedState);
+ .setRequestedVisibilities(requestedVisibilities);
getController().onInsetsModified(mDisplayContent.getImeTarget(IME_TARGET_INPUT));
// Send our spy window (app) into the system so that we can detect the invocation.
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 5af68021..e3c38b0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -859,6 +859,40 @@
}
@Test
+ public void testFreezeTaskListOrder_replaceTask() {
+ // Create two tasks with the same affinity
+ Task affinityTask1 = createTaskBuilder(".AffinityTask1")
+ .setFlags(FLAG_ACTIVITY_NEW_TASK)
+ .build();
+ Task affinityTask2 = createTaskBuilder(".AffinityTask2")
+ .setFlags(FLAG_ACTIVITY_NEW_TASK)
+ .build();
+ affinityTask2.affinity = affinityTask1.affinity = "affinity";
+
+ // Add some tasks
+ mRecentTasks.add(mTasks.get(0));
+ mRecentTasks.add(affinityTask1);
+ mRecentTasks.add(mTasks.get(1));
+ mCallbacksRecorder.clear();
+
+ // Freeze the list
+ mRecentTasks.setFreezeTaskListReordering();
+ assertTrue(mRecentTasks.isFreezeTaskListReorderingSet());
+
+ // Add the affinity task
+ mRecentTasks.add(affinityTask2);
+
+ assertRecentTasksOrder(mTasks.get(1),
+ affinityTask2,
+ mTasks.get(0));
+
+ assertThat(mCallbacksRecorder.mAdded).hasSize(1);
+ assertThat(mCallbacksRecorder.mAdded).contains(affinityTask2);
+ assertThat(mCallbacksRecorder.mRemoved).hasSize(1);
+ assertThat(mCallbacksRecorder.mRemoved).contains(affinityTask1);
+ }
+
+ @Test
public void testFreezeTaskListOrder_timeout() {
// Add some tasks
mRecentTasks.add(mTasks.get(0));
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 e32b2aa..cac948c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
+++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
@@ -270,4 +270,10 @@
public SurfaceControl.Transaction setColorSpace(SurfaceControl sc, ColorSpace colorSpace) {
return this;
}
+
+ @Override
+ public SurfaceControl.Transaction setTrustedOverlay(SurfaceControl sc,
+ boolean isTrustedOverlay) {
+ return this;
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index ac981cf..c35f317 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -16,8 +16,6 @@
package com.android.server.wm;
-import static android.window.TaskFragmentOrganizer.putExceptionInBundle;
-
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.testing.Assert.assertThrows;
@@ -35,7 +33,6 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
-import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
@@ -44,6 +41,7 @@
import android.window.TaskFragmentCreationParams;
import android.window.TaskFragmentInfo;
import android.window.TaskFragmentOrganizer;
+import android.window.TaskFragmentOrganizerToken;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import android.window.WindowContainerTransactionCallback;
@@ -65,6 +63,7 @@
private TaskFragmentOrganizerController mController;
private TaskFragmentOrganizer mOrganizer;
+ private TaskFragmentOrganizerToken mOrganizerToken;
private ITaskFragmentOrganizer mIOrganizer;
private TaskFragment mTaskFragment;
private TaskFragmentInfo mTaskFragmentInfo;
@@ -76,7 +75,8 @@
public void setup() {
mController = mWm.mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController;
mOrganizer = new TaskFragmentOrganizer(Runnable::run);
- mIOrganizer = mOrganizer.getIOrganizer();
+ mOrganizerToken = mOrganizer.getOrganizerToken();
+ mIOrganizer = ITaskFragmentOrganizer.Stub.asInterface(mOrganizerToken.asBinder());
mTaskFragmentInfo = mock(TaskFragmentInfo.class);
mFragmentToken = new Binder();
mTaskFragment =
@@ -198,9 +198,11 @@
public void testOnTaskFragmentError() throws RemoteException {
final IBinder errorCallbackToken = new Binder();
final Throwable exception = new IllegalArgumentException("Test exception");
- final Bundle exceptionBundle = putExceptionInBundle(exception);
- mIOrganizer.onTaskFragmentError(errorCallbackToken, exceptionBundle);
+ mController.registerOrganizer(mIOrganizer);
+ mController.onTaskFragmentError(mTaskFragment.getTaskFragmentOrganizer(),
+ errorCallbackToken, exception);
+ mController.dispatchPendingEvents();
verify(mOrganizer).onTaskFragmentError(eq(errorCallbackToken), eq(exception));
}
@@ -236,7 +238,7 @@
});
// Allow transaction to change a TaskFragment created by the organizer.
- mTaskFragment.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */);
+ mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* pid */);
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
}
@@ -258,7 +260,7 @@
});
// Allow transaction to change a TaskFragment created by the organizer.
- mTaskFragment.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */);
+ mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* pid */);
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
}
@@ -281,7 +283,7 @@
});
// Allow transaction to change a TaskFragment created by the organizer.
- mTaskFragment.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */);
+ mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* pid */);
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
}
@@ -307,8 +309,8 @@
});
// Allow transaction to change a TaskFragment created by the organizer.
- mTaskFragment.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */);
- taskFragment2.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */);
+ mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* pid */);
+ taskFragment2.setTaskFragmentOrganizer(mOrganizerToken, 10 /* pid */);
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
}
@@ -318,10 +320,13 @@
mOrganizer.applyTransaction(mTransaction);
// Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
- mTransaction.createTaskFragment(mock(TaskFragmentCreationParams.class));
+ final TaskFragmentCreationParams mockParams = mock(TaskFragmentCreationParams.class);
+ doReturn(mOrganizerToken).when(mockParams).getOrganizer();
+ mTransaction.createTaskFragment(mockParams);
mTransaction.startActivityInTaskFragment(
- mFragmentToken, new Intent(), null /* activityOptions */);
+ mFragmentToken, null /* callerToken */, new Intent(), null /* activityOptions */);
mTransaction.reparentActivityToTaskFragment(mFragmentToken, mock(IBinder.class));
+ mTransaction.setAdjacentTaskFragments(mFragmentToken, mock(IBinder.class));
// It is expected to fail for the mock TaskFragmentCreationParams. It is ok as we are
// testing the security check here.
@@ -352,7 +357,7 @@
});
// Allow transaction to change a TaskFragment created by the organizer.
- mTaskFragment.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */);
+ mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* pid */);
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index efe6538..316309c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -35,6 +35,7 @@
import android.view.Gravity;
import android.view.InsetsSource;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.WindowManager;
import androidx.test.filters.FlakyTest;
@@ -276,7 +277,9 @@
imeFrame.top = 400;
imeSource.setFrame(imeFrame);
imeSource.setVisible(true);
- w.updateRequestedVisibility(state);
+ final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+ requestedVisibilities.setVisibility(ITYPE_IME, true);
+ w.setRequestedVisibilities(requestedVisibilities);
w.mAboveInsetsState.addSource(imeSource);
// With no insets or system decor all the frames incoming from PhoneWindowManager
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 83cdc3ba..a91298f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -56,6 +56,7 @@
import android.view.IWindowSessionCallback;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.View;
import android.view.WindowManager;
@@ -278,7 +279,7 @@
.getWindowType(eq(windowContextToken));
mWm.addWindow(session, new TestIWindow(), params, View.VISIBLE, DEFAULT_DISPLAY,
- UserHandle.USER_SYSTEM, new InsetsState(), null, new InsetsState(),
+ UserHandle.USER_SYSTEM, new InsetsVisibilities(), null, new InsetsState(),
new InsetsSourceControl[0]);
verify(mWm.mWindowContextListenerController, never()).registerWindowContainerListener(any(),
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index e83db78..17288c2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -85,6 +85,7 @@
import android.view.InputWindowHandle;
import android.view.InsetsSource;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.SurfaceControl;
import android.view.WindowManager;
@@ -437,9 +438,9 @@
.setWindow(statusBar, null /* frameProvider */, null /* imeFrameProvider */);
mDisplayContent.getInsetsStateController().onBarControlTargetChanged(
app, null /* fakeTopControlling */, app, null /* fakeNavControlling */);
- final InsetsState state = new InsetsState();
- state.getSource(ITYPE_STATUS_BAR).setVisible(false);
- app.updateRequestedVisibility(state);
+ final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+ requestedVisibilities.setVisibility(ITYPE_STATUS_BAR, false);
+ app.setRequestedVisibilities(requestedVisibilities);
mDisplayContent.getInsetsStateController().getSourceProvider(ITYPE_STATUS_BAR)
.updateClientVisibility(app);
waitUntilHandlersIdle();
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index e408cfc..965f126 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -87,14 +87,14 @@
*/
final class HotwordDetectionConnection {
private static final String TAG = "HotwordDetectionConnection";
- // TODO (b/177502877): Set the Debug flag to false before shipping.
- static final boolean DEBUG = true;
+ static final boolean DEBUG = false;
// TODO: These constants need to be refined.
private static final long VALIDATION_TIMEOUT_MILLIS = 3000;
private static final long MAX_UPDATE_TIMEOUT_MILLIS = 6000;
private static final Duration MAX_UPDATE_TIMEOUT_DURATION =
Duration.ofMillis(MAX_UPDATE_TIMEOUT_MILLIS);
+ private static final long RESET_DEBUG_HOTWORD_LOGGING_TIMEOUT_MILLIS = 60 * 60 * 1000; // 1 hour
private final Executor mAudioCopyExecutor = Executors.newCachedThreadPool();
// TODO: This may need to be a Handler(looper)
@@ -103,6 +103,7 @@
private final AtomicBoolean mUpdateStateAfterStartFinished = new AtomicBoolean(false);
private final IBinder.DeathRecipient mAudioServerDeathRecipient = this::audioServerDied;
private final @NonNull ServiceConnectionFactory mServiceConnectionFactory;
+ private final IHotwordRecognitionStatusCallback mCallback;
final Object mLock;
final int mVoiceInteractionServiceUid;
@@ -110,11 +111,11 @@
final int mUser;
final Context mContext;
volatile HotwordDetectionServiceIdentity mIdentity;
- private IHotwordRecognitionStatusCallback mCallback;
private IMicrophoneHotwordDetectionVoiceInteractionCallback mSoftwareCallback;
private Instant mLastRestartInstant;
private ScheduledFuture<?> mCancellationTaskFuture;
+ private ScheduledFuture<?> mDebugHotwordLoggingTimeoutFuture = null;
/** Identity used for attributing app ops when delivering data to the Interactor. */
@GuardedBy("mLock")
@@ -128,17 +129,24 @@
private boolean mPerformingSoftwareHotwordDetection;
private @NonNull ServiceConnection mRemoteHotwordDetectionService;
private IBinder mAudioFlinger;
+ private boolean mDebugHotwordLogging = false;
HotwordDetectionConnection(Object lock, Context context, int voiceInteractionServiceUid,
Identity voiceInteractorIdentity, ComponentName serviceName, int userId,
boolean bindInstantServiceAllowed, @Nullable PersistableBundle options,
- @Nullable SharedMemory sharedMemory, IHotwordRecognitionStatusCallback callback) {
+ @Nullable SharedMemory sharedMemory,
+ @NonNull IHotwordRecognitionStatusCallback callback) {
+ if (callback == null) {
+ Slog.w(TAG, "Callback is null while creating connection");
+ throw new IllegalArgumentException("Callback is null while creating connection");
+ }
mLock = lock;
mContext = context;
mVoiceInteractionServiceUid = voiceInteractionServiceUid;
mVoiceInteractorIdentity = voiceInteractorIdentity;
mDetectionComponentName = serviceName;
mUser = userId;
+ mCallback = callback;
final Intent intent = new Intent(HotwordDetectionService.SERVICE_INTERFACE);
intent.setComponent(mDetectionComponentName);
initAudioFlingerLocked();
@@ -147,22 +155,13 @@
mRemoteHotwordDetectionService = mServiceConnectionFactory.createLocked();
- if (callback == null) {
- updateStateLocked(options, sharedMemory);
- return;
- }
- mCallback = callback;
-
mLastRestartInstant = Instant.now();
updateStateAfterProcessStart(options, sharedMemory);
// TODO(volnov): we need to be smarter here, e.g. schedule it a bit more often, but wait
// until the current session is closed.
mCancellationTaskFuture = mScheduledExecutorService.scheduleAtFixedRate(() -> {
- if (DEBUG) {
- Slog.i(TAG, "Time to restart the process, TTL has passed");
- }
-
+ Slog.v(TAG, "Time to restart the process, TTL has passed");
synchronized (mLock) {
restartProcessLocked();
}
@@ -268,9 +267,9 @@
}
void cancelLocked() {
- if (DEBUG) {
- Slog.d(TAG, "cancelLocked");
- }
+ Slog.v(TAG, "cancelLocked");
+ clearDebugHotwordLoggingTimeoutLocked();
+ mDebugHotwordLogging = false;
if (mRemoteHotwordDetectionService.isBound()) {
mRemoteHotwordDetectionService.unbind();
LocalServices.getService(PermissionManagerServiceInternal.class)
@@ -288,6 +287,7 @@
// TODO(b/191742511): this logic needs a test
if (!mUpdateStateAfterStartFinished.get()
&& Instant.now().minus(MAX_UPDATE_TIMEOUT_DURATION).isBefore(mLastRestartInstant)) {
+ Slog.v(TAG, "call updateStateAfterProcessStart");
updateStateAfterProcessStart(options, sharedMemory);
} else {
mRemoteHotwordDetectionService.run(
@@ -330,6 +330,9 @@
if (result != null) {
Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result)
+ " bits from hotword trusted process");
+ if (mDebugHotwordLogging) {
+ Slog.i(TAG, "Egressed detected result: " + result);
+ }
}
} else {
Slog.i(TAG, "Hotword detection has already completed");
@@ -407,15 +410,11 @@
private void detectFromDspSourceForTest(SoundTrigger.KeyphraseRecognitionEvent recognitionEvent,
IHotwordRecognitionStatusCallback externalCallback) {
- if (DEBUG) {
- Slog.d(TAG, "detectFromDspSourceForTest");
- }
+ Slog.v(TAG, "detectFromDspSourceForTest");
IDspHotwordDetectionCallback internalCallback = new IDspHotwordDetectionCallback.Stub() {
@Override
public void onDetected(HotwordDetectedResult result) throws RemoteException {
- if (DEBUG) {
- Slog.d(TAG, "onDetected");
- }
+ Slog.v(TAG, "onDetected");
synchronized (mLock) {
if (mValidatingDspTrigger) {
mValidatingDspTrigger = false;
@@ -424,6 +423,9 @@
if (result != null) {
Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result)
+ " bits from hotword trusted process");
+ if (mDebugHotwordLogging) {
+ Slog.i(TAG, "Egressed detected result: " + result);
+ }
}
} else {
Slog.i(TAG, "Ignored hotword detected since trigger has been handled");
@@ -433,13 +435,14 @@
@Override
public void onRejected(HotwordRejectedResult result) throws RemoteException {
- if (DEBUG) {
- Slog.d(TAG, "onRejected");
- }
+ Slog.v(TAG, "onRejected");
synchronized (mLock) {
if (mValidatingDspTrigger) {
mValidatingDspTrigger = false;
externalCallback.onRejected(result);
+ if (mDebugHotwordLogging && result != null) {
+ Slog.i(TAG, "Egressed rejected result: " + result);
+ }
} else {
Slog.i(TAG, "Ignored hotword rejected since trigger has been handled");
}
@@ -482,6 +485,9 @@
if (result != null) {
Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result)
+ " bits from hotword trusted process");
+ if (mDebugHotwordLogging) {
+ Slog.i(TAG, "Egressed detected result: " + result);
+ }
}
}
}
@@ -498,6 +504,9 @@
}
mValidatingDspTrigger = false;
externalCallback.onRejected(result);
+ if (mDebugHotwordLogging && result != null) {
+ Slog.i(TAG, "Egressed rejected result: " + result);
+ }
}
}
};
@@ -514,19 +523,37 @@
}
void forceRestart() {
- if (DEBUG) {
- Slog.i(TAG, "Requested to restart the service internally. Performing the restart");
- }
+ Slog.v(TAG, "Requested to restart the service internally. Performing the restart");
synchronized (mLock) {
restartProcessLocked();
}
}
- private void restartProcessLocked() {
- if (DEBUG) {
- Slog.i(TAG, "Restarting hotword detection process");
- }
+ void setDebugHotwordLoggingLocked(boolean logging) {
+ Slog.v(TAG, "setDebugHotwordLoggingLocked: " + logging);
+ clearDebugHotwordLoggingTimeoutLocked();
+ mDebugHotwordLogging = logging;
+ if (logging) {
+ // Reset mDebugHotwordLogging to false after one hour
+ mDebugHotwordLoggingTimeoutFuture = mScheduledExecutorService.schedule(() -> {
+ Slog.v(TAG, "Timeout to reset mDebugHotwordLogging to false");
+ synchronized (mLock) {
+ mDebugHotwordLogging = false;
+ }
+ }, RESET_DEBUG_HOTWORD_LOGGING_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ }
+ }
+
+ private void clearDebugHotwordLoggingTimeoutLocked() {
+ if (mDebugHotwordLoggingTimeoutFuture != null) {
+ mDebugHotwordLoggingTimeoutFuture.cancel(/* mayInterruptIfRunning= */true);
+ mDebugHotwordLoggingTimeoutFuture = null;
+ }
+ }
+
+ private void restartProcessLocked() {
+ Slog.v(TAG, "Restarting hotword detection process");
ServiceConnection oldConnection = mRemoteHotwordDetectionService;
// TODO(volnov): this can be done after connect() has been successful.
@@ -547,9 +574,7 @@
// Recreate connection to reset the cache.
mRemoteHotwordDetectionService = mServiceConnectionFactory.createLocked();
- if (DEBUG) {
- Slog.i(TAG, "Started the new process, issuing #onProcessRestarted");
- }
+ Slog.v(TAG, "Started the new process, issuing #onProcessRestarted");
try {
mCallback.onProcessRestarted();
} catch (RemoteException e) {
@@ -700,6 +725,9 @@
bestEffortClose(serviceAudioSource);
bestEffortClose(audioSource);
+ if (mDebugHotwordLogging && result != null) {
+ Slog.i(TAG, "Egressed rejected result: " + result);
+ }
// TODO: Propagate the HotwordRejectedResult.
}
@@ -714,6 +742,9 @@
if (triggerResult != null) {
Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(
triggerResult) + " bits from hotword trusted process");
+ if (mDebugHotwordLogging) {
+ Slog.i(TAG, "Egressed detected result: " + triggerResult);
+ }
}
// TODO: Add a delay before closing.
bestEffortClose(audioSource);
@@ -773,9 +804,7 @@
}
synchronized (mLock) {
if (!mRespectServiceConnectionStatusChanged) {
- if (DEBUG) {
- Slog.d(TAG, "Ignored onServiceConnectionStatusChanged event");
- }
+ Slog.v(TAG, "Ignored onServiceConnectionStatusChanged event");
return;
}
mIsBound = connected;
@@ -792,9 +821,7 @@
super.binderDied();
synchronized (mLock) {
if (!mRespectServiceConnectionStatusChanged) {
- if (DEBUG) {
- Slog.d(TAG, "Ignored #binderDied event");
- }
+ Slog.v(TAG, "Ignored #binderDied event");
return;
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index ccf4267..71541ad 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -832,6 +832,17 @@
mImpl.forceRestartHotwordDetector();
}
+ // Called by Shell command
+ void setDebugHotwordLogging(boolean logging) {
+ synchronized (this) {
+ if (mImpl == null) {
+ Slog.w(TAG, "setTemporaryLogging without running voice interaction service");
+ return;
+ }
+ mImpl.setDebugHotwordLoggingLocked(logging);
+ }
+ }
+
@Override
public void showSession(Bundle args, int flags) {
synchronized (this) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index cbcbf52..558a9ac 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -79,8 +79,7 @@
class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConnection.Callback {
final static String TAG = "VoiceInteractionServiceManager";
- // TODO (b/177502877): Set the Debug flag to false before shipping.
- static final boolean DEBUG = true;
+ static final boolean DEBUG = false;
final static String CLOSE_REASON_VOICE_INTERACTION = "voiceinteraction";
@@ -420,9 +419,7 @@
@Nullable PersistableBundle options,
@Nullable SharedMemory sharedMemory,
IHotwordRecognitionStatusCallback callback) {
- if (DEBUG) {
- Slog.d(TAG, "updateStateLocked");
- }
+ Slog.v(TAG, "updateStateLocked");
if (mHotwordDetectionComponentName == null) {
Slog.w(TAG, "Hotword detection service name not found");
throw new IllegalStateException("Hotword detection service name not found");
@@ -584,6 +581,14 @@
mHotwordDetectionConnection.forceRestart();
}
+ void setDebugHotwordLoggingLocked(boolean logging) {
+ if (mHotwordDetectionConnection == null) {
+ Slog.w(TAG, "Failed to set temporary debug logging: no hotword detection active");
+ return;
+ }
+ mHotwordDetectionConnection.setDebugHotwordLoggingLocked(logging);
+ }
+
void resetHotwordDetectionConnectionLocked() {
if (DEBUG) {
Slog.d(TAG, "resetHotwordDetectionConnectionLocked");
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java
index cdd8f7b..9bdf4e4 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java
@@ -56,6 +56,8 @@
return requestDisable(pw);
case "restart-detection":
return requestRestartDetection(pw);
+ case "set-debug-hotword-logging":
+ return setDebugHotwordLogging(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -76,9 +78,14 @@
pw.println("");
pw.println(" disable [true|false]");
pw.println(" Temporarily disable (when true) service");
+ pw.println("");
pw.println(" restart-detection");
pw.println(" Force a restart of a hotword detection service");
pw.println("");
+ pw.println(" set-debug-hotword-logging [true|false]");
+ pw.println(" Temporarily enable or disable debug logging for hotword result.");
+ pw.println(" The debug logging will be reset after one hour from last enable.");
+ pw.println("");
}
}
@@ -157,6 +164,17 @@
return 0;
}
+ private int setDebugHotwordLogging(PrintWriter pw) {
+ boolean logging = Boolean.parseBoolean(getNextArgRequired());
+ Slog.i(TAG, "setDebugHotwordLogging(): " + logging);
+ try {
+ mService.setDebugHotwordLogging(logging);
+ } catch (Exception e) {
+ return handleError(pw, "setDebugHotwordLogging()", e);
+ }
+ return 0;
+ }
+
private static int handleError(PrintWriter pw, String message, Exception e) {
Slog.e(TAG, "error calling " + message, e);
pw.printf("Error calling %s: %s\n", message, e);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index f01519f..72ad23b 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3538,7 +3538,7 @@
"nr_advanced_capable_pco_id_int";
/**
- * This configuration allows the framework to use user data communication to detect RRC state,
+ * This configuration allows the framework to use user data communication to detect Idle state,
* and this is used on the 5G icon.
*
* There is a new way for for RRC state detection at Android 12. If
@@ -3546,16 +3546,23 @@
* {@link TelephonyManager#CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED}) returns true,
* then framework can use PHYSICAL_CHANNEL_CONFIG for RRC state detection. Based on this
* condition, some carriers want to use the legacy behavior that way is using user data
- * communication to detect the RRC state. Therefore, this configuration allows the framework
- * to use user data communication to detect RRC state.
+ * communication to detect the Idle state. Therefore, this configuration allows the framework
+ * to use user data communication to detect Idle state.
*
- * The precondition is
+ * There are 3 situations reflects the carrier define Idle state.
+ * 1. using PHYSICAL_CHANNEL_CONFIG to detect RRC Idle
+ * 2. using all of data connections to detect RRC Idle.
+ * 3. using data communication(consider internet data connection only) to detect data Idle.
+ *
+ * How to setup for above 3 cases?
+ * For below part, we call the condition#1 is device support
* {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported}(
- * {@link TelephonyManager#CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED}) returns true,
- * otherwise this config is not working.
- * If this is true, framework uses the user data communication for RRC state detection.
- * If this is false, framework uses the PHYSICAL_CHANNEL_CONFIG for RRC state detection.
+ * {@link TelephonyManager#CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED}).
+ * The condition#2 is carrier enable the KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL.
*
+ * For case#1, the condition#1 is true and the condition#2 is false.
+ * For case#2, the condition#1 is false and the condition#2 is false.
+ * For case#3, the condition#2 is true.
* @hide
*/
public static final String KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL =
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index 72150dd..6ada32e 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -178,7 +178,7 @@
mCsiSinr = inRangeOrUnavailable(csiSinr, -23, 23);
mCsiCqiTableIndex = inRangeOrUnavailable(csiCqiTableIndex, 1, 3);
mCsiCqiReport = csiCqiReport.stream()
- .map(cqi -> new Integer(inRangeOrUnavailable(Byte.toUnsignedInt(cqi), 1, 3)))
+ .map(cqi -> new Integer(inRangeOrUnavailable(Byte.toUnsignedInt(cqi), 0, 15)))
.collect(Collectors.toList());
mSsRsrp = inRangeOrUnavailable(ssRsrp, -140, -44);
mSsRsrq = inRangeOrUnavailable(ssRsrq, -43, 20);
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index 1aa0499..cac14a7 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -32,6 +32,7 @@
test_suites: ["general-tests"],
java_resources: [
":com.android.apex.apkrollback.test_v2",
+ ":StagedInstallTestApexV2",
":StagedInstallTestApexV2_WrongSha",
":test.rebootless_apex_v1",
":test.rebootless_apex_v2",
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index 738e68e..4684f01 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -55,8 +55,11 @@
private static final TestApp TEST_APEX_WITH_APK_V2 = new TestApp("TestApexWithApkV2",
APK_IN_APEX_TESTAPEX_NAME, 2, /*isApex*/true, APK_IN_APEX_TESTAPEX_NAME + "_v2.apex");
private static final TestApp APEX_WRONG_SHA_V2 = new TestApp(
- "ApexWrongSha2", SHIM_APEX_PACKAGE_NAME, 2, /*isApex*/true,
+ "ApexWrongSha2", SHIM_APEX_PACKAGE_NAME, 2, /* isApex= */ true,
"com.android.apex.cts.shim.v2_wrong_sha.apex");
+ private static final TestApp APEX_V2 = new TestApp(
+ "ApexV2", SHIM_APEX_PACKAGE_NAME, 2, /* isApex= */ true,
+ "com.android.apex.cts.shim.v2.apex");
private File mTestStateFile = new File(
InstrumentationRegistry.getInstrumentation().getContext().getFilesDir(),
@@ -237,6 +240,96 @@
}
@Test
+ public void testApexInstallerNotInAllowListCanNotInstall_staged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
+ // We don't really care which APEX we are trying to install here, since the session creation
+ // should fail immediately.
+ InstallUtils.commitExpectingFailure(
+ SecurityException.class,
+ "Installer not allowed to commit staged install",
+ Install.single(APEX_WRONG_SHA_V2).setBypassStangedInstallerCheck(false)
+ .setStaged());
+ }
+
+ @Test
+ public void testApexInstallerNotInAllowListCanNotInstall_nonStaged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
+ // We don't really care which APEX we are trying to install here, since the session creation
+ // should fail immediately.
+ InstallUtils.commitExpectingFailure(
+ SecurityException.class,
+ "Installer not allowed to commit non-staged APEX install",
+ Install.single(APEX_WRONG_SHA_V2).setBypassStangedInstallerCheck(false));
+ }
+
+ @Test
+ public void testApexNotInAllowListCanNotInstall_staged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ InstallUtils.commitExpectingFailure(
+ AssertionError.class,
+ "Update of APEX package test.apex.rebootless is not allowed "
+ + "for com.android.tests.stagedinstallinternal",
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false).setStaged());
+ }
+
+ @Test
+ public void testApexNotInAllowListCanNotInstall_nonStaged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ InstallUtils.commitExpectingFailure(
+ AssertionError.class,
+ "Update of APEX package test.apex.rebootless is not allowed "
+ + "for com.android.tests.stagedinstallinternal",
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false));
+ }
+
+ @Test
+ public void testVendorApexWrongInstaller_staged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ InstallUtils.commitExpectingFailure(
+ AssertionError.class,
+ "Update of APEX package test.apex.rebootless is not allowed "
+ + "for com.android.tests.stagedinstallinternal",
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false).setStaged());
+ }
+
+ @Test
+ public void testVendorApexWrongInstaller_nonStaged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ InstallUtils.commitExpectingFailure(
+ AssertionError.class,
+ "Update of APEX package test.apex.rebootless is not allowed "
+ + "for com.android.tests.stagedinstallinternal",
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false));
+ }
+
+ @Test
+ public void testVendorApexCorrectInstaller_staged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ int sessionId =
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false).setStaged().commit();
+ InstallUtils.getPackageInstaller().abandonSession(sessionId);
+ }
+
+ @Test
+ public void testVendorApexCorrectInstaller_nonStaged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false).commit();
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(2);
+ }
+
+ @Test
public void testRebootlessUpdates() throws Exception {
InstallUtils.dropShellPermissionIdentity();
InstallUtils.adoptShellPermissionIdentity(Manifest.permission.INSTALL_PACKAGE_UPDATES);
@@ -298,6 +391,19 @@
}
}
+ @Test
+ public void testRebootlessUpdate_hasStagedSessionWithSameApex_fails() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
+
+ int sessionId = Install.single(APEX_V2).setStaged().commit();
+ assertSessionReady(sessionId);
+ InstallUtils.commitExpectingFailure(
+ AssertionError.class,
+ "Staged session " + sessionId + " already contains " + SHIM_APEX_PACKAGE_NAME,
+ Install.single(APEX_V2));
+
+ }
+
private static void assertSessionApplied(int sessionId) {
assertSessionState(sessionId, (session) -> {
assertThat(session.isStagedSessionApplied()).isTrue();
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index 3bd3767..5021009 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -43,7 +43,9 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.BufferedWriter;
import java.io.File;
+import java.io.FileWriter;
import java.util.List;
import java.util.stream.Collectors;
@@ -60,6 +62,9 @@
private static final String APK_A = "TestAppAv1.apk";
private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
+ private static final String TEST_VENDOR_APEX_ALLOW_LIST =
+ "/vendor/etc/sysconfig/test-vendor-apex-allow-list.xml";
+
private final InstallUtilsHost mHostUtils = new InstallUtilsHost(this);
/**
@@ -87,7 +92,8 @@
"/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
"/data/apex/active/" + SHIM_APEX_PACKAGE_NAME + "*.apex",
"/system/apex/test.rebootless_apex_v1.apex",
- "/data/apex/active/test.apex.rebootless*.apex");
+ "/data/apex/active/test.apex.rebootless*.apex",
+ TEST_VENDOR_APEX_ALLOW_LIST);
}
@Before
@@ -134,7 +140,23 @@
}
getDevice().remountSystemWritable();
assertTrue(getDevice().pushFile(apex, "/system/apex/" + fileName));
- getDevice().reboot();
+ }
+
+ private void pushTestVendorApexAllowList(String installerPackageName) throws Exception {
+ if (!getDevice().isAdbRoot()) {
+ getDevice().enableAdbRoot();
+ }
+ getDevice().remountSystemWritable();
+ File file = File.createTempFile("test-vendor-apex-allow-list", ".xml");
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
+ final String fmt =
+ "<config>\n"
+ + " <allowed-vendor-apex package=\"test.apex.rebootless\" "
+ + " installerPackage=\"%s\" />\n"
+ + "</config>";
+ writer.write(String.format(fmt, installerPackageName));
+ }
+ getDevice().pushFile(file, TEST_VENDOR_APEX_ALLOW_LIST);
}
/**
@@ -144,6 +166,8 @@
@LargeTest
public void testDuplicateApkInApexShouldFail() throws Exception {
pushTestApex(APK_IN_APEX_TESTAPEX_NAME + "_v1.apex");
+ getDevice().reboot();
+
runPhase("testDuplicateApkInApexShouldFail_Commit");
getDevice().reboot();
runPhase("testDuplicateApkInApexShouldFail_Verify");
@@ -389,11 +413,71 @@
}
@Test
+ public void testApexInstallerNotInAllowListCanNotInstall() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ runPhase("testApexInstallerNotInAllowListCanNotInstall_staged");
+ runPhase("testApexInstallerNotInAllowListCanNotInstall_nonStaged");
+ }
+
+ @Test
+ @LargeTest
+ public void testApexNotInAllowListCanNotInstall() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ pushTestApex("test.rebootless_apex_v1.apex");
+ getDevice().reboot();
+
+ runPhase("testApexNotInAllowListCanNotInstall_staged");
+ runPhase("testApexNotInAllowListCanNotInstall_nonStaged");
+ }
+
+ @Test
+ @LargeTest
+ public void testVendorApexWrongInstaller() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ pushTestVendorApexAllowList("com.wrong.installer");
+ pushTestApex("test.rebootless_apex_v1.apex");
+ getDevice().reboot();
+
+ runPhase("testVendorApexWrongInstaller_staged");
+ runPhase("testVendorApexWrongInstaller_nonStaged");
+ }
+
+ @Test
+ @LargeTest
+ public void testVendorApexCorrectInstaller() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ pushTestVendorApexAllowList("com.android.tests.stagedinstallinternal");
+ pushTestApex("test.rebootless_apex_v1.apex");
+ getDevice().reboot();
+
+ runPhase("testVendorApexCorrectInstaller_staged");
+ runPhase("testVendorApexCorrectInstaller_nonStaged");
+ }
+
+ @Test
public void testRebootlessUpdates() throws Exception {
pushTestApex("test.rebootless_apex_v1.apex");
+ getDevice().reboot();
+
runPhase("testRebootlessUpdates");
}
+ @Test
+ public void testRebootlessUpdate_hasStagedSessionWithSameApex_fails() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ runPhase("testRebootlessUpdate_hasStagedSessionWithSameApex_fails");
+ }
+
private List<String> getStagingDirectories() throws DeviceNotAvailableException {
String baseDir = "/data/app-staging";
try {