diff options
226 files changed, 4135 insertions, 1523 deletions
diff --git a/apct-tests/perftests/core/src/android/libcore/XmlSerializerPerfTest.java b/apct-tests/perftests/core/src/android/libcore/XmlSerializerPerfTest.java new file mode 100644 index 000000000000..412cb5acbf8b --- /dev/null +++ b/apct-tests/perftests/core/src/android/libcore/XmlSerializerPerfTest.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2022 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.libcore; + +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; +import android.test.suitebuilder.annotation.LargeTest; +import android.util.Xml; + +import androidx.test.runner.AndroidJUnit4; + +import libcore.util.XmlObjectFactory; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.xmlpull.v1.XmlSerializer; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; + +/** + * Compares various kinds of method invocation. + */ +@RunWith(AndroidJUnit4.class) +@LargeTest +public class XmlSerializerPerfTest { + + @Rule + public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + + @Test + public void timeFastSerializer_nonIndent_depth100() throws IOException { + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + XmlSerializer serializer = Xml.newFastSerializer(); + runTest(serializer, 100); + } + } + + @Test + public void timeFastSerializer_indent_depth100() throws IOException { + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + XmlSerializer serializer = Xml.newFastSerializer(); + serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); + runTest(serializer, 100); + } + } + + @Test + public void timeKXmlSerializer_nonIndent_depth100() throws IOException { + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + XmlSerializer serializer = XmlObjectFactory.newXmlSerializer(); + runTest(serializer, 100); + } + } + + @Test + public void timeKXmlSerializer_indent_depth100() throws IOException { + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + XmlSerializer serializer = XmlObjectFactory.newXmlSerializer(); + serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); + runTest(serializer, 100); + } + } + + private void runTest(XmlSerializer serializer, int depth) throws IOException { + File file = File.createTempFile(XmlSerializerPerfTest.class.getSimpleName(), "tmp"); + try (OutputStream out = new FileOutputStream(file)) { + serializer.setOutput(out, StandardCharsets.UTF_8.name()); + serializer.startDocument(null, true); + writeContent(serializer, depth); + serializer.endDocument(); + } + } + + private void writeContent(XmlSerializer serializer, int depth) throws IOException { + serializer.startTag(null, "tag"); + serializer.attribute(null, "attribute", "value1"); + if (depth > 0) { + writeContent(serializer, depth - 1); + } + serializer.endTag(null, "tag"); + } + +} diff --git a/core/api/current.txt b/core/api/current.txt index c70fa37a0674..cc1451266ac8 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -23192,6 +23192,7 @@ package android.media { method public int describeContents(); method @Nullable public String getClientPackageName(); method public int getConnectionState(); + method @NonNull public java.util.Set<java.lang.String> getDeduplicationIds(); method @Nullable public CharSequence getDescription(); method @Nullable public android.os.Bundle getExtras(); method @NonNull public java.util.List<java.lang.String> getFeatures(); @@ -23225,6 +23226,7 @@ package android.media { method @NonNull public android.media.MediaRoute2Info.Builder clearFeatures(); method @NonNull public android.media.MediaRoute2Info.Builder setClientPackageName(@Nullable String); method @NonNull public android.media.MediaRoute2Info.Builder setConnectionState(int); + method @NonNull public android.media.MediaRoute2Info.Builder setDeduplicationIds(@NonNull java.util.Set<java.lang.String>); method @NonNull public android.media.MediaRoute2Info.Builder setDescription(@Nullable CharSequence); method @NonNull public android.media.MediaRoute2Info.Builder setExtras(@Nullable android.os.Bundle); method @NonNull public android.media.MediaRoute2Info.Builder setIconUri(@Nullable android.net.Uri); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 1e4023eeee18..186e5be92524 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -134,7 +134,7 @@ package android.app { method public static void resumeAppSwitches() throws android.os.RemoteException; method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void setStopUserOnSwitch(int); - method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean startUserInBackgroundOnSecondaryDisplay(int, int); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public boolean startUserInBackgroundOnSecondaryDisplay(int, int); method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean stopUser(int, boolean); method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public boolean updateMccMncConfiguration(@NonNull String, @NonNull String); method @RequiresPermission(android.Manifest.permission.DUMP) public void waitForBroadcastIdle(); diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 576b572dcc9a..cb7b478d73b4 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -4401,7 +4401,7 @@ public class ActivityManager { */ @TestApi @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, - android.Manifest.permission.CREATE_USERS}) + android.Manifest.permission.INTERACT_ACROSS_USERS}) public boolean startUserInBackgroundOnSecondaryDisplay(@UserIdInt int userId, int displayId) { if (!UserManager.isUsersOnSecondaryDisplaysEnabled()) { diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java index c2df8022af0f..13da1901e559 100644 --- a/core/java/android/app/BroadcastOptions.java +++ b/core/java/android/app/BroadcastOptions.java @@ -16,6 +16,7 @@ package android.app; +import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; @@ -34,6 +35,10 @@ import android.os.PowerExemptionManager; import android.os.PowerExemptionManager.ReasonCode; import android.os.PowerExemptionManager.TempAllowListType; +import com.android.internal.util.Preconditions; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Objects; /** @@ -59,6 +64,8 @@ public class BroadcastOptions extends ComponentOptions { private boolean mIsAlarmBroadcast = false; private long mIdForResponseEvent; private @Nullable IntentFilter mRemoveMatchingFilter; + private @DeliveryGroupPolicy int mDeliveryGroupPolicy; + private @Nullable String mDeliveryGroupKey; /** * Change ID which is invalid. @@ -190,6 +197,46 @@ public class BroadcastOptions extends ComponentOptions { private static final String KEY_REMOVE_MATCHING_FILTER = "android:broadcast.removeMatchingFilter"; + /** + * Corresponds to {@link #setDeliveryGroupPolicy(int)}. + */ + private static final String KEY_DELIVERY_GROUP_POLICY = + "android:broadcast.deliveryGroupPolicy"; + + /** + * Corresponds to {@link #setDeliveryGroupKey(String, String)}. + */ + private static final String KEY_DELIVERY_GROUP_KEY = + "android:broadcast.deliveryGroupKey"; + + /** + * The list of delivery group policies which specify how multiple broadcasts belonging to + * the same delivery group has to be handled. + * @hide + */ + @IntDef(flag = true, prefix = { "DELIVERY_GROUP_POLICY_" }, value = { + DELIVERY_GROUP_POLICY_ALL, + DELIVERY_GROUP_POLICY_MOST_RECENT, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DeliveryGroupPolicy {} + + /** + * Delivery group policy that indicates that all the broadcasts in the delivery group + * need to be delivered as is. + * + * @hide + */ + public static final int DELIVERY_GROUP_POLICY_ALL = 0; + + /** + * Delivery group policy that indicates that only the most recent broadcast in the delivery + * group need to be delivered and the rest can be dropped. + * + * @hide + */ + public static final int DELIVERY_GROUP_POLICY_MOST_RECENT = 1; + public static BroadcastOptions makeBasic() { BroadcastOptions opts = new BroadcastOptions(); return opts; @@ -236,6 +283,9 @@ public class BroadcastOptions extends ComponentOptions { mIsAlarmBroadcast = opts.getBoolean(KEY_ALARM_BROADCAST, false); mRemoveMatchingFilter = opts.getParcelable(KEY_REMOVE_MATCHING_FILTER, IntentFilter.class); + mDeliveryGroupPolicy = opts.getInt(KEY_DELIVERY_GROUP_POLICY, + DELIVERY_GROUP_POLICY_ALL); + mDeliveryGroupKey = opts.getString(KEY_DELIVERY_GROUP_KEY); } /** @@ -639,6 +689,41 @@ public class BroadcastOptions extends ComponentOptions { } /** + * Set delivery group policy for this broadcast to specify how multiple broadcasts belonging to + * the same delivery group has to be handled. + * + * @hide + */ + public void setDeliveryGroupPolicy(@DeliveryGroupPolicy int policy) { + mDeliveryGroupPolicy = policy; + } + + /** @hide */ + public @DeliveryGroupPolicy int getDeliveryGroupPolicy() { + return mDeliveryGroupPolicy; + } + + /** + * Set namespace and key to identify the delivery group that this broadcast belongs to. + * If no namespace and key is set, then by default {@link Intent#filterEquals(Intent)} will be + * used to identify the delivery group. + * + * @hide + */ + public void setDeliveryGroupKey(@NonNull String namespace, @NonNull String key) { + Preconditions.checkArgument(!namespace.contains("/"), + "namespace should not contain '/'"); + Preconditions.checkArgument(!key.contains("/"), + "key should not contain '/'"); + mDeliveryGroupKey = namespace + "/" + key; + } + + /** @hide */ + public String getDeliveryGroupKey() { + return mDeliveryGroupKey; + } + + /** * Returns the created options as a Bundle, which can be passed to * {@link android.content.Context#sendBroadcast(android.content.Intent) * Context.sendBroadcast(Intent)} and related methods. @@ -686,6 +771,12 @@ public class BroadcastOptions extends ComponentOptions { if (mRemoveMatchingFilter != null) { b.putParcelable(KEY_REMOVE_MATCHING_FILTER, mRemoveMatchingFilter); } + if (mDeliveryGroupPolicy != DELIVERY_GROUP_POLICY_ALL) { + b.putInt(KEY_DELIVERY_GROUP_POLICY, mDeliveryGroupPolicy); + } + if (mDeliveryGroupKey != null) { + b.putString(KEY_DELIVERY_GROUP_KEY, mDeliveryGroupKey); + } return b.isEmpty() ? null : b; } } diff --git a/core/java/android/app/backup/BackupRestoreEventLogger.java b/core/java/android/app/backup/BackupRestoreEventLogger.java new file mode 100644 index 000000000000..b789b38c966e --- /dev/null +++ b/core/java/android/app/backup/BackupRestoreEventLogger.java @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.backup; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +// TODO(b/244436184): Make this @SystemApi +/** + * Class to log B&R stats for each data type that is backed up and restored by the calling app. + * + * The logger instance is designed to accept a limited number of unique + * {link @BackupRestoreDataType} values, as determined by the underlying implementation. Apps are + * expected to have a small pre-defined set of data type values they use. Attempts to log too many + * unique values will be rejected. + * + * @hide + */ +public class BackupRestoreEventLogger { + /** + * Max number of unique data types for which an instance of this logger can store info. Attempts + * to use more distinct data type values will be rejected. + */ + public static final int DATA_TYPES_ALLOWED = 15; + + /** + * Operation types for which this logger can be used. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + OperationType.BACKUP, + OperationType.RESTORE + }) + @interface OperationType { + int BACKUP = 1; + int RESTORE = 2; + } + + /** + * Denotes that the annotated element identifies a data type as required by the logging methods + * of {@code BackupRestoreEventLogger} + */ + @Retention(RetentionPolicy.SOURCE) + public @interface BackupRestoreDataType {} + + /** + * Denotes that the annotated element identifies an error type as required by the logging + * methods of {@code BackupRestoreEventLogger} + */ + @Retention(RetentionPolicy.SOURCE) + public @interface BackupRestoreError {} + + private final int mOperationType; + + /** + * @param operationType type of the operation for which logging will be performed. See + * {@link OperationType}. Attempts to use logging methods that don't match + * the specified operation type will be rejected (e.g. use backup methods + * for a restore logger and vice versa). + */ + public BackupRestoreEventLogger(@OperationType int operationType) { + mOperationType = operationType; + } + + /** + * Report progress during a backup operation. Call this method for each distinct data type that + * your {@code BackupAgent} implementation handles for any items of that type that have been + * successfully backed up. Repeated calls to this method with the same {@code dataType} will + * increase the total count of items associated with this data type by {@code count}. + * + * This method should be called from a {@link BackupAgent} implementation during an ongoing + * backup operation. + * + * @param dataType the type of data being backed. + * @param count number of items of the given type that have been successfully backed up. + * + * @return boolean, indicating whether the log has been accepted. + */ + public boolean logItemsBackedUp(@NonNull @BackupRestoreDataType String dataType, int count) { + return true; + } + + /** + * Report errors during a backup operation. Call this method whenever items of a certain data + * type failed to back up. Repeated calls to this method with the same {@code dataType} / + * {@code error} will increase the total count of items associated with this data type / error + * by {@code count}. + * + * This method should be called from a {@link BackupAgent} implementation during an ongoing + * backup operation. + * + * @param dataType the type of data being backed. + * @param count number of items of the given type that have failed to back up. + * @param error optional, the error that has caused the failure. + * + * @return boolean, indicating whether the log has been accepted. + */ + public boolean logItemsBackupFailed(@NonNull @BackupRestoreDataType String dataType, int count, + @Nullable @BackupRestoreError String error) { + return true; + } + + /** + * Report metadata associated with a data type that is currently being backed up, e.g. name of + * the selected wallpaper file / package. Repeated calls to this method with the same {@code + * dataType} will overwrite the previously supplied {@code metaData} value. + * + * The logger does not store or transmit the provided metadata value. Instead, it’s replaced + * with the SHA-256 hash of the provided string. + * + * This method should be called from a {@link BackupAgent} implementation during an ongoing + * backup operation. + * + * @param dataType the type of data being backed up. + * @param metaData the metadata associated with the data type. + * + * @return boolean, indicating whether the log has been accepted. + */ + public boolean logBackupMetaData(@NonNull @BackupRestoreDataType String dataType, + @NonNull String metaData) { + return true; + } + + /** + * Report progress during a restore operation. Call this method for each distinct data type that + * your {@code BackupAgent} implementation handles if any items of that type have been + * successfully restored. Repeated calls to this method with the same {@code dataType} will + * increase the total count of items associated with this data type by {@code count}. + * + * This method should either be called from a {@link BackupAgent} implementation during an + * ongoing restore operation or during any delayed restore actions the package had scheduled + * earlier (e.g. complete the restore once a certain dependency becomes available on the + * device). + * + * @param dataType the type of data being restored. + * @param count number of items of the given type that have been successfully restored. + * + * @return boolean, indicating whether the log has been accepted. + */ + public boolean logItemsRestored(@NonNull @BackupRestoreDataType String dataType, int count) { + return true; + } + + /** + * Report errors during a restore operation. Call this method whenever items of a certain data + * type failed to restore. Repeated calls to this method with the same {@code dataType} / + * {@code error} will increase the total count of items associated with this data type / error + * by {@code count}. + * + * This method should either be called from a {@link BackupAgent} implementation during an + * ongoing restore operation or during any delayed restore actions the package had scheduled + * earlier (e.g. complete the restore once a certain dependency becomes available on the + * device). + * + * @param dataType the type of data being restored. + * @param count number of items of the given type that have failed to restore. + * @param error optional, the error that has caused the failure. + * + * @return boolean, indicating whether the log has been accepted. + */ + public boolean logItemsRestoreFailed(@NonNull @BackupRestoreDataType String dataType, int count, + @Nullable @BackupRestoreError String error) { + return true; + } + + /** + * Report metadata associated with a data type that is currently being restored, e.g. name of + * the selected wallpaper file / package. Repeated calls to this method with the same + * {@code dataType} will overwrite the previously supplied {@code metaData} value. + * + * The logger does not store or transmit the provided metadata value. Instead, it’s replaced + * with the SHA-256 hash of the provided string. + * + * This method should either be called from a {@link BackupAgent} implementation during an + * ongoing restore operation or during any delayed restore actions the package had scheduled + * earlier (e.g. complete the restore once a certain dependency becomes available on the + * device). + * + * @param dataType the type of data being restored. + * @param metadata the metadata associated with the data type. + * + * @return boolean, indicating whether the log has been accepted. + */ + public boolean logRestoreMetadata(@NonNull @BackupRestoreDataType String dataType, + @NonNull String metadata) { + return true; + } + + /** + * Get the contents of this logger. This method should only be used by B&R code in Android + * Framework. + * + * @hide + */ + public List<DataTypeResult> getLoggingResults() { + return Collections.emptyList(); + } + + /** + * Get the operation type for which this logger was created. This method should only be used + * by B&R code in Android Framework. + * + * @hide + */ + public @OperationType int getOperationType() { + return mOperationType; + } + + /** + * Encapsulate logging results for a single data type. + */ + public static class DataTypeResult { + @BackupRestoreDataType + private final String mDataType; + private final int mSuccessCount; + private final Map<String, Integer> mErrors; + private final byte[] mMetadataHash; + + public DataTypeResult(String dataType, int successCount, + Map<String, Integer> errors, byte[] metadataHash) { + mDataType = dataType; + mSuccessCount = successCount; + mErrors = errors; + mMetadataHash = metadataHash; + } + + @NonNull + @BackupRestoreDataType + public String getDataType() { + return mDataType; + } + + /** + * @return number of items of the given data type that have been successfully backed up or + * restored. + */ + public int getSuccessCount() { + return mSuccessCount; + } + + /** + * @return mapping of {@link BackupRestoreError} to the count of items that are affected by + * the error. + */ + @NonNull + public Map<String, Integer> getErrors() { + return mErrors; + } + + /** + * @return SHA-256 hash of the metadata or {@code null} of no metadata has been logged for + * this data type. + */ + @Nullable + public byte[] getMetadataHash() { + return mMetadataHash; + } + } +} diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GalleryDebugActivity.kt b/core/java/android/credentials/ui/Constants.java index 23072a231417..aeeede744188 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GalleryDebugActivity.kt +++ b/core/java/android/credentials/ui/Constants.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,8 +14,20 @@ * limitations under the License. */ -package com.android.settingslib.spa.gallery +package android.credentials.ui; -import com.android.settingslib.spa.framework.DebugActivity +/** + * Constants for the ui protocol that doesn't fit into other individual data structures. + * + * @hide + */ +public class Constants { + + /** + * The intent extra key for the {@code ResultReceiver} object when launching the UX + * activities. + */ + public static final String EXTRA_RESULT_RECEIVER = + "android.credentials.ui.extra.RESULT_RECEIVER"; -class GalleryDebugActivity : DebugActivity() +} diff --git a/core/java/android/credentials/ui/IntentFactory.java b/core/java/android/credentials/ui/IntentFactory.java new file mode 100644 index 000000000000..9a038d137434 --- /dev/null +++ b/core/java/android/credentials/ui/IntentFactory.java @@ -0,0 +1,68 @@ +/* + * Copyright 2022 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.credentials.ui; + +import android.content.ComponentName; +import android.content.Intent; +import android.os.Parcel; +import android.os.ResultReceiver; + +import java.util.ArrayList; + +/** + * Helpers for generating the intents and related extras parameters to launch the UI activities. + * + * @hide + */ +public class IntentFactory { + /** Generate a new launch intent to the . */ + public static Intent newIntent(RequestInfo requestInfo, + ArrayList<ProviderData> providerDataList, ResultReceiver resultReceiver) { + Intent intent = new Intent(); + // TODO: define these as proper config strings. + String activityName = "com.androidauth.tatiaccountselector/.CredentialSelectorActivity"; + // String activityName = "com.android.credentialmanager/.CredentialSelectorActivity"; + intent.setComponent(ComponentName.unflattenFromString(activityName)); + + intent.putParcelableArrayListExtra( + ProviderData.EXTRA_PROVIDER_DATA_LIST, providerDataList); + intent.putExtra(RequestInfo.EXTRA_REQUEST_INFO, requestInfo); + intent.putExtra(Constants.EXTRA_RESULT_RECEIVER, + toIpcFriendlyResultReceiver(resultReceiver)); + + return intent; + } + + /** + * Convert an instance of a "locally-defined" ResultReceiver to an instance of + * {@link android.os.ResultReceiver} itself, which the receiving process will be able to + * unmarshall. + */ + private static <T extends ResultReceiver> ResultReceiver toIpcFriendlyResultReceiver( + T resultReceiver) { + final Parcel parcel = Parcel.obtain(); + resultReceiver.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + + final ResultReceiver ipcFriendly = ResultReceiver.CREATOR.createFromParcel(parcel); + parcel.recycle(); + + return ipcFriendly; + } + + private IntentFactory() {} +} diff --git a/core/java/android/credentials/ui/RequestInfo.java b/core/java/android/credentials/ui/RequestInfo.java index 5de6d73945eb..eddb519051a9 100644 --- a/core/java/android/credentials/ui/RequestInfo.java +++ b/core/java/android/credentials/ui/RequestInfo.java @@ -36,12 +36,6 @@ public class RequestInfo implements Parcelable { */ public static final @NonNull String EXTRA_REQUEST_INFO = "android.credentials.ui.extra.REQUEST_INFO"; - /** - * The intent extra key for the {@code ResultReceiver} object when launching the UX - * activities. - */ - public static final @NonNull String EXTRA_RESULT_RECEIVER = - "android.credentials.ui.extra.RESULT_RECEIVER"; /** Type value for an executeGetCredential request. */ public static final @NonNull String TYPE_GET = "android.credentials.ui.TYPE_GET"; diff --git a/core/java/android/hardware/input/VirtualDpad.java b/core/java/android/hardware/input/VirtualDpad.java index d7cda9ec33cf..4d61553ccb52 100644 --- a/core/java/android/hardware/input/VirtualDpad.java +++ b/core/java/android/hardware/input/VirtualDpad.java @@ -24,7 +24,6 @@ import android.os.IBinder; import android.os.RemoteException; import android.view.KeyEvent; -import java.io.Closeable; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; @@ -39,7 +38,7 @@ import java.util.Set; * @hide */ @SystemApi -public class VirtualDpad implements Closeable { +public class VirtualDpad extends VirtualInputDevice { private final Set<Integer> mSupportedKeyCodes = Collections.unmodifiableSet( @@ -50,23 +49,10 @@ public class VirtualDpad implements Closeable { KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_CENTER))); - private final IVirtualDevice mVirtualDevice; - private final IBinder mToken; /** @hide */ public VirtualDpad(IVirtualDevice virtualDevice, IBinder token) { - mVirtualDevice = virtualDevice; - mToken = token; - } - - @Override - @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) - public void close() { - try { - mVirtualDevice.unregisterInputDevice(mToken); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + super(virtualDevice, token); } /** diff --git a/core/java/android/hardware/input/VirtualInputDevice.java b/core/java/android/hardware/input/VirtualInputDevice.java new file mode 100644 index 000000000000..2a79ef0e0afd --- /dev/null +++ b/core/java/android/hardware/input/VirtualInputDevice.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2022 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.hardware.input; + +import android.annotation.RequiresPermission; +import android.companion.virtual.IVirtualDevice; +import android.os.IBinder; +import android.os.RemoteException; + +import java.io.Closeable; + +/** + * The base class for all virtual input devices such as VirtualKeyboard, VirtualMouse. + * This implements the shared functionality such as closing the device and keeping track of + * identifiers. + * + * @hide + */ +abstract class VirtualInputDevice implements Closeable { + + /** + * The virtual device to which this VirtualInputDevice belongs to. + */ + protected final IVirtualDevice mVirtualDevice; + + /** + * The token used to uniquely identify the virtual input device. + */ + protected final IBinder mToken; + + /** @hide */ + VirtualInputDevice( + IVirtualDevice virtualDevice, IBinder token) { + mVirtualDevice = virtualDevice; + mToken = token; + } + + + @Override + @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) + public void close() { + try { + mVirtualDevice.unregisterInputDevice(mToken); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } +} diff --git a/core/java/android/hardware/input/VirtualKeyboard.java b/core/java/android/hardware/input/VirtualKeyboard.java index 901401fea32c..e569dbf6b6b6 100644 --- a/core/java/android/hardware/input/VirtualKeyboard.java +++ b/core/java/android/hardware/input/VirtualKeyboard.java @@ -24,8 +24,6 @@ import android.os.IBinder; import android.os.RemoteException; import android.view.KeyEvent; -import java.io.Closeable; - /** * A virtual keyboard representing a key input mechanism on a remote device, such as a built-in * keyboard on a laptop, a software keyboard on a tablet, or a keypad on a TV remote control. @@ -36,26 +34,13 @@ import java.io.Closeable; * @hide */ @SystemApi -public class VirtualKeyboard implements Closeable { +public class VirtualKeyboard extends VirtualInputDevice { private final int mUnsupportedKeyCode = KeyEvent.KEYCODE_DPAD_CENTER; - private final IVirtualDevice mVirtualDevice; - private final IBinder mToken; /** @hide */ public VirtualKeyboard(IVirtualDevice virtualDevice, IBinder token) { - mVirtualDevice = virtualDevice; - mToken = token; - } - - @Override - @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) - public void close() { - try { - mVirtualDevice.unregisterInputDevice(mToken); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + super(virtualDevice, token); } /** diff --git a/core/java/android/hardware/input/VirtualMouse.java b/core/java/android/hardware/input/VirtualMouse.java index 6e2b56a2b5bc..7eba2b8bfdf0 100644 --- a/core/java/android/hardware/input/VirtualMouse.java +++ b/core/java/android/hardware/input/VirtualMouse.java @@ -25,8 +25,6 @@ import android.os.IBinder; import android.os.RemoteException; import android.view.MotionEvent; -import java.io.Closeable; - /** * A virtual mouse representing a relative input mechanism on a remote device, such as a mouse or * trackpad. @@ -37,25 +35,11 @@ import java.io.Closeable; * @hide */ @SystemApi -public class VirtualMouse implements Closeable { - - private final IVirtualDevice mVirtualDevice; - private final IBinder mToken; +public class VirtualMouse extends VirtualInputDevice { /** @hide */ public VirtualMouse(IVirtualDevice virtualDevice, IBinder token) { - mVirtualDevice = virtualDevice; - mToken = token; - } - - @Override - @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) - public void close() { - try { - mVirtualDevice.unregisterInputDevice(mToken); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + super(virtualDevice, token); } /** diff --git a/core/java/android/hardware/input/VirtualTouchscreen.java b/core/java/android/hardware/input/VirtualTouchscreen.java index c8d602acaff6..0d07753b9b60 100644 --- a/core/java/android/hardware/input/VirtualTouchscreen.java +++ b/core/java/android/hardware/input/VirtualTouchscreen.java @@ -23,8 +23,6 @@ import android.companion.virtual.IVirtualDevice; import android.os.IBinder; import android.os.RemoteException; -import java.io.Closeable; - /** * A virtual touchscreen representing a touch-based display input mechanism on a remote device. * @@ -34,25 +32,10 @@ import java.io.Closeable; * @hide */ @SystemApi -public class VirtualTouchscreen implements Closeable { - - private final IVirtualDevice mVirtualDevice; - private final IBinder mToken; - +public class VirtualTouchscreen extends VirtualInputDevice { /** @hide */ public VirtualTouchscreen(IVirtualDevice virtualDevice, IBinder token) { - mVirtualDevice = virtualDevice; - mToken = token; - } - - @Override - @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) - public void close() { - try { - mVirtualDevice.unregisterInputDevice(mToken); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + super(virtualDevice, token); } /** diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index 4df013949de5..d3a6323230a5 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -1246,8 +1246,21 @@ public class Binder implements IBinder { // If the call was {@link IBinder#FLAG_ONEWAY} then these exceptions // disappear into the ether. final boolean tagEnabled = Trace.isTagEnabled(Trace.TRACE_TAG_AIDL); + final boolean hasFullyQualifiedName = getMaxTransactionId() > 0; final String transactionTraceName; - if (tagEnabled) { + + if (tagEnabled && hasFullyQualifiedName) { + // If tracing enabled and we have a fully qualified name, fetch the name + transactionTraceName = getTransactionTraceName(code); + } else if (tagEnabled && isStackTrackingEnabled()) { + // If tracing is enabled and we *don't* have a fully qualified name, fetch the + // 'best effort' name only for stack tracking. This works around noticeable perf impact + // on low latency binder calls (<100us). The tracing call itself is between (1-10us) and + // the perf impact can be quite noticeable while benchmarking such binder calls. + // The primary culprits are ContentProviders and Cursors which convenienty don't + // autogenerate their AIDL and hence will not have a fully qualified name. + // + // TODO(b/253426478): Relax this constraint after a more robust fix transactionTraceName = getTransactionTraceName(code); } else { transactionTraceName = null; diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java index f62cc879cce3..8afd6de235a0 100644 --- a/core/java/android/os/PowerManagerInternal.java +++ b/core/java/android/os/PowerManagerInternal.java @@ -341,4 +341,10 @@ public abstract class PowerManagerInternal { * device is not awake. */ public abstract void nap(long eventTime, boolean allowWake); + + /** + * Returns true if ambient display is suppressed by any app with any token. This method will + * return false if ambient display is not available. + */ + public abstract boolean isAmbientDisplaySuppressed(); } diff --git a/core/java/android/service/dreams/DreamActivity.java b/core/java/android/service/dreams/DreamActivity.java index f6a7c8eb8c4b..a2fa1392b079 100644 --- a/core/java/android/service/dreams/DreamActivity.java +++ b/core/java/android/service/dreams/DreamActivity.java @@ -44,6 +44,8 @@ import android.text.TextUtils; public class DreamActivity extends Activity { static final String EXTRA_CALLBACK = "binder"; static final String EXTRA_DREAM_TITLE = "title"; + @Nullable + private DreamService.DreamActivityCallbacks mCallback; public DreamActivity() {} @@ -57,11 +59,19 @@ public class DreamActivity extends Activity { } final Bundle extras = getIntent().getExtras(); - final DreamService.DreamActivityCallback callback = - (DreamService.DreamActivityCallback) extras.getBinder(EXTRA_CALLBACK); + mCallback = (DreamService.DreamActivityCallbacks) extras.getBinder(EXTRA_CALLBACK); - if (callback != null) { - callback.onActivityCreated(this); + if (mCallback != null) { + mCallback.onActivityCreated(this); } } + + @Override + public void onDestroy() { + if (mCallback != null) { + mCallback.onActivityDestroyed(); + } + + super.onDestroy(); + } } diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index 3c1fef02f9ba..cb0dce91589e 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -1295,7 +1295,7 @@ public class DreamService extends Service implements Window.Callback { Intent i = new Intent(this, DreamActivity.class); i.setPackage(getApplicationContext().getPackageName()); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - i.putExtra(DreamActivity.EXTRA_CALLBACK, new DreamActivityCallback(mDreamToken)); + i.putExtra(DreamActivity.EXTRA_CALLBACK, new DreamActivityCallbacks(mDreamToken)); final ServiceInfo serviceInfo = fetchServiceInfo(this, new ComponentName(this, getClass())); i.putExtra(DreamActivity.EXTRA_DREAM_TITLE, fetchDreamLabel(this, serviceInfo)); @@ -1488,10 +1488,10 @@ public class DreamService extends Service implements Window.Callback { } /** @hide */ - final class DreamActivityCallback extends Binder { + final class DreamActivityCallbacks extends Binder { private final IBinder mActivityDreamToken; - DreamActivityCallback(IBinder token) { + DreamActivityCallbacks(IBinder token) { mActivityDreamToken = token; } @@ -1516,6 +1516,12 @@ public class DreamService extends Service implements Window.Callback { mActivity = activity; onWindowCreated(activity.getWindow()); } + + // If DreamActivity is destroyed, wake up from Dream. + void onActivityDestroyed() { + mActivity = null; + onDestroy(); + } } /** diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index b559161ae0ad..a59d429b24e6 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -284,7 +284,6 @@ public abstract class WallpaperService extends Service { private Display mDisplay; private Context mDisplayContext; private int mDisplayState; - private @Surface.Rotation int mDisplayInstallOrientation; private float mWallpaperDimAmount = 0.05f; private float mPreviousWallpaperDimAmount = mWallpaperDimAmount; private float mDefaultDimAmount = mWallpaperDimAmount; @@ -1159,7 +1158,7 @@ public abstract class WallpaperService extends Service { mSurfaceControl, mInsetsState, mTempControls, mSyncSeqIdBundle); final int transformHint = SurfaceControl.rotationToBufferTransform( - (mDisplayInstallOrientation + mDisplay.getRotation()) % 4); + (mDisplay.getInstallOrientation() + mDisplay.getRotation()) % 4); mSurfaceControl.setTransformHint(transformHint); WindowLayout.computeSurfaceSize(mLayout, maxBounds, mWidth, mHeight, mWinFrames.frame, false /* dragResizing */, mSurfaceSize); @@ -1420,7 +1419,6 @@ public abstract class WallpaperService extends Service { mWallpaperDimAmount = mDefaultDimAmount; mPreviousWallpaperDimAmount = mWallpaperDimAmount; mDisplayState = mDisplay.getState(); - mDisplayInstallOrientation = mDisplay.getInstallOrientation(); if (DEBUG) Log.v(TAG, "onCreate(): " + this); onCreate(mSurfaceHolder); diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java index a1ece9298e7f..a0a07b30662f 100644 --- a/core/java/android/view/HandwritingInitiator.java +++ b/core/java/android/view/HandwritingInitiator.java @@ -162,7 +162,13 @@ public class HandwritingInitiator { if (candidateView == getConnectedView()) { startHandwriting(candidateView); } else { - candidateView.requestFocus(); + if (candidateView.getRevealOnFocusHint()) { + candidateView.setRevealOnFocusHint(false); + candidateView.requestFocus(); + candidateView.setRevealOnFocusHint(true); + } else { + candidateView.requestFocus(); + } } } } diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java index 4de7c4fdd513..43828d58afc4 100644 --- a/core/java/android/view/ImeFocusController.java +++ b/core/java/android/view/ImeFocusController.java @@ -108,10 +108,11 @@ public final class ImeFocusController { } /** - * @see InputMethodManager#checkFocus() + * @see ViewRootImpl#dispatchCheckFocus() */ - public boolean checkFocus(boolean forceNewFocus, boolean startInput) { - return getImmDelegate().checkFocus(forceNewFocus, startInput, mViewRootImpl); + @UiThread + void onScheduledCheckFocus() { + getImmDelegate().onScheduledCheckFocus(mViewRootImpl); } @UiThread @@ -163,7 +164,7 @@ public final class ImeFocusController { void onPostWindowGainedFocus(View viewForWindowFocus, @NonNull WindowManager.LayoutParams windowAttribute); void onViewFocusChanged(@NonNull View view, boolean hasFocus); - boolean checkFocus(boolean forceNewFocus, boolean startInput, ViewRootImpl viewRootImpl); + void onScheduledCheckFocus(@NonNull ViewRootImpl viewRootImpl); void onViewDetachedFromWindow(View view, ViewRootImpl viewRootImpl); void onWindowDismissed(ViewRootImpl viewRootImpl); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 58c81260076b..bfa13507ed50 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -428,8 +428,6 @@ public final class ViewRootImpl implements ViewParent, final DisplayManager mDisplayManager; final String mBasePackageName; - private @Surface.Rotation int mDisplayInstallOrientation; - final int[] mTmpLocation = new int[2]; final TypedValue mTmpValue = new TypedValue(); @@ -1134,7 +1132,6 @@ public final class ViewRootImpl implements ViewParent, if (mView == null) { mView = view; - mDisplayInstallOrientation = mDisplay.getInstallOrientation(); mViewLayoutDirectionInitial = mView.getRawLayoutDirection(); mFallbackEventHandler.setView(view); mWindowAttributes.copyFrom(attrs); @@ -1905,7 +1902,6 @@ public final class ViewRootImpl implements ViewParent, updateInternalDisplay(displayId, mView.getResources()); mImeFocusController.onMovedToDisplay(); mAttachInfo.mDisplayState = mDisplay.getState(); - mDisplayInstallOrientation = mDisplay.getInstallOrientation(); // Internal state updated, now notify the view hierarchy. mView.dispatchMovedToDisplay(mDisplay, config); } @@ -5718,7 +5714,7 @@ public final class ViewRootImpl implements ViewParent, enqueueInputEvent(event, null, 0, true); } break; case MSG_CHECK_FOCUS: { - getImeFocusController().checkFocus(false, true); + getImeFocusController().onScheduledCheckFocus(); } break; case MSG_CLOSE_SYSTEM_DIALOGS: { if (mView != null) { @@ -8235,7 +8231,7 @@ public final class ViewRootImpl implements ViewParent, } final int transformHint = SurfaceControl.rotationToBufferTransform( - (mDisplayInstallOrientation + mDisplay.getRotation()) % 4); + (mDisplay.getInstallOrientation() + mDisplay.getRotation()) % 4); WindowLayout.computeSurfaceSize(mWindowAttributes, winConfig.getMaxBounds(), requestedWidth, requestedHeight, mWinFrameInScreen, mPendingDragResizing, mSurfaceSize); @@ -8260,7 +8256,7 @@ public final class ViewRootImpl implements ViewParent, } mLastTransformHint = transformHint; - + mSurfaceControl.setTransformHint(transformHint); if (mAttachInfo.mContentCaptureManager != null) { diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 18b3e212d6f4..eab3f2de44bf 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -776,12 +776,12 @@ public final class InputMethodManager { "InputMethodManager.DelegateImpl#startInputAsyncOnWindowFocusGain", InputMethodManager.this, null /* icProto */); - final ImeFocusController controller = getFocusController(); - if (controller == null) { - return; - } - + final ViewRootImpl viewRootImpl; synchronized (mH) { + if (mCurRootView == null) { + return; + } + viewRootImpl = mCurRootView; if (mRestartOnNextWindowFocus) { if (DEBUG) Log.v(TAG, "Restarting due to mRestartOnNextWindowFocus as true"); mRestartOnNextWindowFocus = false; @@ -789,7 +789,7 @@ public final class InputMethodManager { } } - if (controller.checkFocus(forceNewFocus, false)) { + if (checkFocusInternal(forceNewFocus, false, viewRootImpl)) { // We need to restart input on the current focus view. This // should be done in conjunction with telling the system service // about the window gaining focus, to help make the transition @@ -825,9 +825,8 @@ public final class InputMethodManager { } @Override - public boolean checkFocus(boolean forceNewFocus, boolean startInput, - ViewRootImpl viewRootImpl) { - return checkFocusInternal(forceNewFocus, startInput, viewRootImpl); + public void onScheduledCheckFocus(@NonNull ViewRootImpl viewRootImpl) { + checkFocusInternal(false, true, viewRootImpl); } @Override @@ -937,15 +936,6 @@ public final class InputMethodManager { return mCurRootView != null ? mNextServedView : null; } - private ImeFocusController getFocusController() { - synchronized (mH) { - if (mCurRootView != null) { - return mCurRootView.getImeFocusController(); - } - return null; - } - } - /** * Returns {@code true} when the given view has been served by Input Method. */ @@ -1128,8 +1118,7 @@ public final class InputMethodManager { if (mCurRootView == null) { return; } - if (!mCurRootView.getImeFocusController().checkFocus( - mRestartOnNextWindowFocus, false)) { + if (!checkFocusInternal(mRestartOnNextWindowFocus, false, mCurRootView)) { return; } final int reason = active ? StartInputReason.ACTIVATED_BY_IMMS @@ -2658,19 +2647,25 @@ public final class InputMethodManager { } /** - * Check the next served view from {@link ImeFocusController} if needs to start input. * Note that this method should *NOT* be called inside of {@code mH} lock to prevent start input * background thread may blocked by other methods which already inside {@code mH} lock. * @hide */ @UnsupportedAppUsage public void checkFocus() { - final ImeFocusController controller = getFocusController(); - if (controller != null) { - controller.checkFocus(false /* forceNewFocus */, true /* startInput */); + final ViewRootImpl viewRootImpl; + synchronized (mH) { + if (mCurRootView == null) { + return; + } + viewRootImpl = mCurRootView; } + checkFocusInternal(false /* forceNewFocus */, true /* startInput */, viewRootImpl); } + /** + * Check the next served view if needs to start input. + */ private boolean checkFocusInternal(boolean forceNewFocus, boolean startInput, ViewRootImpl viewRootImpl) { synchronized (mH) { diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml index a7f2aa7cba69..be1c939f0ff8 100644 --- a/core/res/res/layout/notification_template_header.xml +++ b/core/res/res/layout/notification_template_header.xml @@ -24,6 +24,7 @@ android:gravity="center_vertical" android:orientation="horizontal" android:theme="@style/Theme.DeviceDefault.Notification" + android:importantForAccessibility="no" > <ImageView diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioManagerTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioManagerTest.java new file mode 100644 index 000000000000..259a11852784 --- /dev/null +++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioManagerTest.java @@ -0,0 +1,490 @@ +/* + * Copyright (C) 2022 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.hardware.radio.tests.unittests; + +import static com.google.common.truth.Truth.assertWithMessage; + +import android.hardware.radio.ProgramSelector; +import android.hardware.radio.RadioManager; + +import org.junit.Test; + +public final class RadioManagerTest { + + private static final int REGION = RadioManager.REGION_ITU_2; + private static final int FM_LOWER_LIMIT = 87500; + private static final int FM_UPPER_LIMIT = 108000; + private static final int FM_SPACING = 200; + private static final int AM_LOWER_LIMIT = 540; + private static final int AM_UPPER_LIMIT = 1700; + private static final int AM_SPACING = 10; + private static final boolean STEREO_SUPPORTED = true; + private static final boolean RDS_SUPPORTED = true; + private static final boolean TA_SUPPORTED = false; + private static final boolean AF_SUPPORTED = false; + private static final boolean EA_SUPPORTED = false; + + private static final int PROPERTIES_ID = 10; + private static final String SERVICE_NAME = "ServiceNameMock"; + private static final int CLASS_ID = RadioManager.CLASS_AM_FM; + private static final String IMPLEMENTOR = "ImplementorMock"; + private static final String PRODUCT = "ProductMock"; + private static final String VERSION = "VersionMock"; + private static final String SERIAL = "SerialMock"; + private static final int NUM_TUNERS = 1; + private static final int NUM_AUDIO_SOURCES = 1; + private static final boolean IS_INITIALIZATION_REQUIRED = false; + private static final boolean IS_CAPTURE_SUPPORTED = false; + private static final boolean IS_BG_SCAN_SUPPORTED = true; + private static final int[] SUPPORTED_PROGRAM_TYPES = new int[]{ + ProgramSelector.PROGRAM_TYPE_AM, ProgramSelector.PROGRAM_TYPE_FM}; + private static final int[] SUPPORTED_IDENTIFIERS_TYPES = new int[]{ + ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, ProgramSelector.IDENTIFIER_TYPE_RDS_PI}; + + private static final RadioManager.FmBandDescriptor FM_BAND_DESCRIPTOR = + createFmBandDescriptor(); + private static final RadioManager.AmBandDescriptor AM_BAND_DESCRIPTOR = + createAmBandDescriptor(); + private static final RadioManager.FmBandConfig FM_BAND_CONFIG = createFmBandConfig(); + private static final RadioManager.AmBandConfig AM_BAND_CONFIG = createAmBandConfig(); + private static final RadioManager.ModuleProperties AMFM_PROPERTIES = createAmFmProperties(); + + @Test + public void getType_forBandDescriptor() { + RadioManager.BandDescriptor bandDescriptor = createAmBandDescriptor(); + + assertWithMessage("AM Band Descriptor type") + .that(bandDescriptor.getType()).isEqualTo(RadioManager.BAND_AM); + } + + @Test + public void getRegion_forBandDescriptor() { + RadioManager.BandDescriptor bandDescriptor = createFmBandDescriptor(); + + assertWithMessage("FM Band Descriptor region") + .that(bandDescriptor.getRegion()).isEqualTo(REGION); + } + + @Test + public void getLowerLimit_forBandDescriptor() { + RadioManager.BandDescriptor bandDescriptor = createFmBandDescriptor(); + + assertWithMessage("FM Band Descriptor lower limit") + .that(bandDescriptor.getLowerLimit()).isEqualTo(FM_LOWER_LIMIT); + } + + @Test + public void getUpperLimit_forBandDescriptor() { + RadioManager.BandDescriptor bandDescriptor = createAmBandDescriptor(); + + assertWithMessage("AM Band Descriptor upper limit") + .that(bandDescriptor.getUpperLimit()).isEqualTo(AM_UPPER_LIMIT); + } + + @Test + public void getSpacing_forBandDescriptor() { + RadioManager.BandDescriptor bandDescriptor = createAmBandDescriptor(); + + assertWithMessage("AM Band Descriptor spacing") + .that(bandDescriptor.getSpacing()).isEqualTo(AM_SPACING); + } + + @Test + public void isAmBand_forAmBandDescriptor_returnsTrue() { + RadioManager.BandDescriptor bandDescriptor = createAmBandDescriptor(); + + assertWithMessage("Is AM Band Descriptor an AM band") + .that(bandDescriptor.isAmBand()).isTrue(); + } + + @Test + public void isFmBand_forAmBandDescriptor_returnsFalse() { + RadioManager.BandDescriptor bandDescriptor = createAmBandDescriptor(); + + assertWithMessage("Is AM Band Descriptor an FM band") + .that(bandDescriptor.isFmBand()).isFalse(); + } + + @Test + public void isStereoSupported_forFmBandDescriptor() { + assertWithMessage("FM Band Descriptor stereo") + .that(FM_BAND_DESCRIPTOR.isStereoSupported()).isEqualTo(STEREO_SUPPORTED); + } + + @Test + public void isRdsSupported_forFmBandDescriptor() { + assertWithMessage("FM Band Descriptor RDS or RBDS") + .that(FM_BAND_DESCRIPTOR.isRdsSupported()).isEqualTo(RDS_SUPPORTED); + } + + @Test + public void isTaSupported_forFmBandDescriptor() { + assertWithMessage("FM Band Descriptor traffic announcement") + .that(FM_BAND_DESCRIPTOR.isTaSupported()).isEqualTo(TA_SUPPORTED); + } + + @Test + public void isAfSupported_forFmBandDescriptor() { + assertWithMessage("FM Band Descriptor alternate frequency") + .that(FM_BAND_DESCRIPTOR.isAfSupported()).isEqualTo(AF_SUPPORTED); + } + + @Test + public void isEaSupported_forFmBandDescriptor() { + assertWithMessage("FM Band Descriptor emergency announcement") + .that(FM_BAND_DESCRIPTOR.isEaSupported()).isEqualTo(EA_SUPPORTED); + } + + @Test + public void isStereoSupported_forAmBandDescriptor() { + assertWithMessage("AM Band Descriptor stereo") + .that(AM_BAND_DESCRIPTOR.isStereoSupported()).isEqualTo(STEREO_SUPPORTED); + } + + @Test + public void equals_withSameFmBandDescriptors_returnsTrue() { + RadioManager.FmBandDescriptor fmBandDescriptor1 = createFmBandDescriptor(); + RadioManager.FmBandDescriptor fmBandDescriptor2 = createFmBandDescriptor(); + + assertWithMessage("The same FM Band Descriptor") + .that(fmBandDescriptor1).isEqualTo(fmBandDescriptor2); + } + + @Test + public void equals_withSameAmBandDescriptors_returnsTrue() { + RadioManager.AmBandDescriptor amBandDescriptorCompared = createAmBandDescriptor(); + + assertWithMessage("The same AM Band Descriptor") + .that(AM_BAND_DESCRIPTOR).isEqualTo(amBandDescriptorCompared); + } + + @Test + public void equals_withAmBandDescriptorsOfDifferentUpperLimits_returnsFalse() { + RadioManager.AmBandDescriptor amBandDescriptorCompared = + new RadioManager.AmBandDescriptor(REGION, RadioManager.BAND_AM, AM_LOWER_LIMIT, + AM_UPPER_LIMIT + AM_SPACING, AM_SPACING, STEREO_SUPPORTED); + + assertWithMessage("AM Band Descriptor of different upper limit") + .that(AM_BAND_DESCRIPTOR).isNotEqualTo(amBandDescriptorCompared); + } + + @Test + public void equals_withAmAndFmBandDescriptors_returnsFalse() { + assertWithMessage("AM Band Descriptor") + .that(AM_BAND_DESCRIPTOR).isNotEqualTo(FM_BAND_DESCRIPTOR); + } + + @Test + public void getType_forBandConfig() { + RadioManager.BandConfig fmBandConfig = createFmBandConfig(); + + assertWithMessage("FM Band Config type") + .that(fmBandConfig.getType()).isEqualTo(RadioManager.BAND_FM); + } + + @Test + public void getRegion_forBandConfig() { + RadioManager.BandConfig amBandConfig = createAmBandConfig(); + + assertWithMessage("AM Band Config region") + .that(amBandConfig.getRegion()).isEqualTo(REGION); + } + + @Test + public void getLowerLimit_forBandConfig() { + RadioManager.BandConfig amBandConfig = createAmBandConfig(); + + assertWithMessage("AM Band Config lower limit") + .that(amBandConfig.getLowerLimit()).isEqualTo(AM_LOWER_LIMIT); + } + + @Test + public void getUpperLimit_forBandConfig() { + RadioManager.BandConfig fmBandConfig = createFmBandConfig(); + + assertWithMessage("FM Band Config upper limit") + .that(fmBandConfig.getUpperLimit()).isEqualTo(FM_UPPER_LIMIT); + } + + @Test + public void getSpacing_forBandConfig() { + RadioManager.BandConfig fmBandConfig = createFmBandConfig(); + + assertWithMessage("FM Band Config spacing") + .that(fmBandConfig.getSpacing()).isEqualTo(FM_SPACING); + } + + @Test + public void getStereo_forFmBandConfig() { + assertWithMessage("FM Band Config stereo ") + .that(FM_BAND_CONFIG.getStereo()).isEqualTo(STEREO_SUPPORTED); + } + + @Test + public void getRds_forFmBandConfig() { + assertWithMessage("FM Band Config RDS or RBDS") + .that(FM_BAND_CONFIG.getRds()).isEqualTo(RDS_SUPPORTED); + } + + @Test + public void getTa_forFmBandConfig() { + assertWithMessage("FM Band Config traffic announcement") + .that(FM_BAND_CONFIG.getTa()).isEqualTo(TA_SUPPORTED); + } + + @Test + public void getAf_forFmBandConfig() { + assertWithMessage("FM Band Config alternate frequency") + .that(FM_BAND_CONFIG.getAf()).isEqualTo(AF_SUPPORTED); + } + + @Test + public void getEa_forFmBandConfig() { + assertWithMessage("FM Band Config emergency Announcement") + .that(FM_BAND_CONFIG.getEa()).isEqualTo(EA_SUPPORTED); + } + + @Test + public void getStereo_forAmBandConfig() { + assertWithMessage("AM Band Config stereo") + .that(AM_BAND_CONFIG.getStereo()).isEqualTo(STEREO_SUPPORTED); + } + + @Test + public void equals_withSameFmBandConfigs_returnsTrue() { + RadioManager.FmBandConfig fmBandConfigCompared = createFmBandConfig(); + + assertWithMessage("The same FM Band Config") + .that(FM_BAND_CONFIG).isEqualTo(fmBandConfigCompared); + } + + @Test + public void equals_withFmBandConfigsOfDifferentAfs_returnsFalse() { + RadioManager.FmBandConfig.Builder builder = new RadioManager.FmBandConfig.Builder( + createFmBandDescriptor()).setStereo(STEREO_SUPPORTED).setRds(RDS_SUPPORTED) + .setTa(TA_SUPPORTED).setAf(!AF_SUPPORTED).setEa(EA_SUPPORTED); + RadioManager.FmBandConfig fmBandConfigFromBuilder = builder.build(); + + assertWithMessage("FM Band Config of different af value") + .that(FM_BAND_CONFIG).isNotEqualTo(fmBandConfigFromBuilder); + } + + @Test + public void equals_withFmAndAmBandConfigs_returnsFalse() { + assertWithMessage("FM Band Config") + .that(FM_BAND_CONFIG).isNotEqualTo(AM_BAND_CONFIG); + } + + @Test + public void equals_withSameAmBandConfigs_returnsTrue() { + RadioManager.AmBandConfig amBandConfigCompared = createAmBandConfig(); + + assertWithMessage("The same AM Band Config") + .that(AM_BAND_CONFIG).isEqualTo(amBandConfigCompared); + } + + @Test + public void equals_withAmBandConfigsOfDifferentTypes_returnsFalse() { + RadioManager.AmBandConfig amBandConfigCompared = new RadioManager.AmBandConfig( + new RadioManager.AmBandDescriptor(REGION, RadioManager.BAND_AM_HD, AM_LOWER_LIMIT, + AM_UPPER_LIMIT, AM_SPACING, STEREO_SUPPORTED)); + + assertWithMessage("AM Band Config of different type") + .that(AM_BAND_CONFIG).isNotEqualTo(amBandConfigCompared); + } + + @Test + public void equals_withAmBandConfigsOfDifferentStereoValues_returnsFalse() { + RadioManager.AmBandConfig.Builder builder = new RadioManager.AmBandConfig.Builder( + createAmBandDescriptor()).setStereo(!STEREO_SUPPORTED); + RadioManager.AmBandConfig amBandConfigFromBuilder = builder.build(); + + assertWithMessage("AM Band Config of different stereo value") + .that(AM_BAND_CONFIG).isNotEqualTo(amBandConfigFromBuilder); + } + + @Test + public void getId_forModuleProperties() { + assertWithMessage("Properties id") + .that(AMFM_PROPERTIES.getId()).isEqualTo(PROPERTIES_ID); + } + + @Test + public void getServiceName_forModuleProperties() { + assertWithMessage("Properties service name") + .that(AMFM_PROPERTIES.getServiceName()).isEqualTo(SERVICE_NAME); + } + + @Test + public void getClassId_forModuleProperties() { + assertWithMessage("Properties class ID") + .that(AMFM_PROPERTIES.getClassId()).isEqualTo(CLASS_ID); + } + + @Test + public void getImplementor_forModuleProperties() { + assertWithMessage("Properties implementor") + .that(AMFM_PROPERTIES.getImplementor()).isEqualTo(IMPLEMENTOR); + } + + @Test + public void getProduct_forModuleProperties() { + assertWithMessage("Properties product") + .that(AMFM_PROPERTIES.getProduct()).isEqualTo(PRODUCT); + } + + @Test + public void getVersion_forModuleProperties() { + assertWithMessage("Properties version") + .that(AMFM_PROPERTIES.getVersion()).isEqualTo(VERSION); + } + + @Test + public void getSerial_forModuleProperties() { + assertWithMessage("Serial properties") + .that(AMFM_PROPERTIES.getSerial()).isEqualTo(SERIAL); + } + + @Test + public void getNumTuners_forModuleProperties() { + assertWithMessage("Number of tuners in properties") + .that(AMFM_PROPERTIES.getNumTuners()).isEqualTo(NUM_TUNERS); + } + + @Test + public void getNumAudioSources_forModuleProperties() { + assertWithMessage("Number of audio sources in properties") + .that(AMFM_PROPERTIES.getNumAudioSources()).isEqualTo(NUM_AUDIO_SOURCES); + } + + @Test + public void isInitializationRequired_forModuleProperties() { + assertWithMessage("Initialization required in properties") + .that(AMFM_PROPERTIES.isInitializationRequired()) + .isEqualTo(IS_INITIALIZATION_REQUIRED); + } + + @Test + public void isCaptureSupported_forModuleProperties() { + assertWithMessage("Capture support in properties") + .that(AMFM_PROPERTIES.isCaptureSupported()).isEqualTo(IS_CAPTURE_SUPPORTED); + } + + @Test + public void isBackgroundScanningSupported_forModuleProperties() { + assertWithMessage("Background scan support in properties") + .that(AMFM_PROPERTIES.isBackgroundScanningSupported()) + .isEqualTo(IS_BG_SCAN_SUPPORTED); + } + + @Test + public void isProgramTypeSupported_withSupportedType_forModuleProperties() { + assertWithMessage("AM/FM frequency type radio support in properties") + .that(AMFM_PROPERTIES.isProgramTypeSupported( + ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY)) + .isTrue(); + } + + @Test + public void isProgramTypeSupported_withNonSupportedType_forModuleProperties() { + assertWithMessage("DAB frequency type radio support in properties") + .that(AMFM_PROPERTIES.isProgramTypeSupported( + ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY)).isFalse(); + } + + @Test + public void isProgramIdentifierSupported_withSupportedIdentifier_forModuleProperties() { + assertWithMessage("AM/FM frequency identifier radio support in properties") + .that(AMFM_PROPERTIES.isProgramIdentifierSupported( + ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY)).isTrue(); + } + + @Test + public void isProgramIdentifierSupported_withNonSupportedIdentifier_forModuleProperties() { + assertWithMessage("DAB frequency identifier radio support in properties") + .that(AMFM_PROPERTIES.isProgramIdentifierSupported( + ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY)).isFalse(); + } + + @Test + public void getDabFrequencyTable_forModuleProperties() { + assertWithMessage("Properties DAB frequency table") + .that(AMFM_PROPERTIES.getDabFrequencyTable()).isNull(); + } + + @Test + public void getVendorInfo_forModuleProperties() { + assertWithMessage("Properties vendor info") + .that(AMFM_PROPERTIES.getVendorInfo()).isEmpty(); + } + + @Test + public void getBands_forModuleProperties() { + assertWithMessage("Properties bands") + .that(AMFM_PROPERTIES.getBands()).asList() + .containsExactly(AM_BAND_DESCRIPTOR, FM_BAND_DESCRIPTOR); + } + + @Test + public void equals_withSameProperties_returnsTrue() { + RadioManager.ModuleProperties propertiesCompared = createAmFmProperties(); + + assertWithMessage("The same module properties") + .that(AMFM_PROPERTIES).isEqualTo(propertiesCompared); + } + + @Test + public void equals_withModulePropertiesOfDifferentIds_returnsFalse() { + RadioManager.ModuleProperties propertiesDab = new RadioManager.ModuleProperties( + PROPERTIES_ID + 1, SERVICE_NAME, CLASS_ID, IMPLEMENTOR, PRODUCT, VERSION, + SERIAL, NUM_TUNERS, NUM_AUDIO_SOURCES, IS_INITIALIZATION_REQUIRED, + IS_CAPTURE_SUPPORTED, /* bands= */ null, IS_BG_SCAN_SUPPORTED, + SUPPORTED_PROGRAM_TYPES, SUPPORTED_IDENTIFIERS_TYPES, /* dabFrequencyTable= */ null, + /* vendorInfo= */ null); + + assertWithMessage("Module properties of different id") + .that(AMFM_PROPERTIES).isNotEqualTo(propertiesDab); + } + + private static RadioManager.ModuleProperties createAmFmProperties() { + return new RadioManager.ModuleProperties(PROPERTIES_ID, SERVICE_NAME, CLASS_ID, + IMPLEMENTOR, PRODUCT, VERSION, SERIAL, NUM_TUNERS, NUM_AUDIO_SOURCES, + IS_INITIALIZATION_REQUIRED, IS_CAPTURE_SUPPORTED, + new RadioManager.BandDescriptor[]{AM_BAND_DESCRIPTOR, FM_BAND_DESCRIPTOR}, + IS_BG_SCAN_SUPPORTED, SUPPORTED_PROGRAM_TYPES, SUPPORTED_IDENTIFIERS_TYPES, + /* dabFrequencyTable= */ null, /* vendorInfo= */ null); + } + + private static RadioManager.FmBandDescriptor createFmBandDescriptor() { + return new RadioManager.FmBandDescriptor(REGION, RadioManager.BAND_FM, FM_LOWER_LIMIT, + FM_UPPER_LIMIT, FM_SPACING, STEREO_SUPPORTED, RDS_SUPPORTED, TA_SUPPORTED, + AF_SUPPORTED, EA_SUPPORTED); + } + + private static RadioManager.AmBandDescriptor createAmBandDescriptor() { + return new RadioManager.AmBandDescriptor(REGION, RadioManager.BAND_AM, AM_LOWER_LIMIT, + AM_UPPER_LIMIT, AM_SPACING, STEREO_SUPPORTED); + } + + private static RadioManager.FmBandConfig createFmBandConfig() { + return new RadioManager.FmBandConfig(createFmBandDescriptor()); + } + + private static RadioManager.AmBandConfig createAmBandConfig() { + return new RadioManager.AmBandConfig(createAmBandDescriptor()); + } +} diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 0bc70857a113..3ee20ea95ee5 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -321,4 +321,21 @@ <!-- The smaller size of the dismiss target (shrinks when something is in the target). --> <dimen name="floating_dismiss_circle_small">120dp</dimen> + + <!-- The thickness of shadows of a window that has focus in DIP. --> + <dimen name="freeform_decor_shadow_focused_thickness">20dp</dimen> + + <!-- The thickness of shadows of a window that doesn't have focus in DIP. --> + <dimen name="freeform_decor_shadow_unfocused_thickness">5dp</dimen> + + <!-- Height of button (32dp) + 2 * margin (5dp each). --> + <dimen name="freeform_decor_caption_height">42dp</dimen> + + <!-- Width of buttons (64dp) + handle (128dp) + padding (24dp total). --> + <dimen name="freeform_decor_caption_width">216dp</dimen> + + <dimen name="freeform_resize_handle">30dp</dimen> + + <dimen name="freeform_resize_corner">44dp</dimen> + </resources> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java index 87700ee4fb50..7d1f130daaef 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java @@ -21,7 +21,6 @@ import android.app.WindowConfiguration; import android.content.Context; import android.content.res.ColorStateList; import android.graphics.Color; -import android.graphics.Rect; import android.graphics.drawable.VectorDrawable; import android.os.Handler; import android.view.Choreographer; @@ -43,22 +42,6 @@ import com.android.wm.shell.desktopmode.DesktopModeStatus; * The shadow's thickness is 20dp when the window is in focus and 5dp when the window isn't. */ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearLayout> { - // The thickness of shadows of a window that has focus in DIP. - private static final int DECOR_SHADOW_FOCUSED_THICKNESS_IN_DIP = 20; - // The thickness of shadows of a window that doesn't have focus in DIP. - private static final int DECOR_SHADOW_UNFOCUSED_THICKNESS_IN_DIP = 5; - - // Height of button (32dp) + 2 * margin (5dp each) - private static final int DECOR_CAPTION_HEIGHT_IN_DIP = 42; - // Width of buttons (64dp) + handle (128dp) + padding (24dp total) - private static final int DECOR_CAPTION_WIDTH_IN_DIP = 216; - private static final int RESIZE_HANDLE_IN_DIP = 30; - private static final int RESIZE_CORNER_IN_DIP = 44; - - private static final Rect EMPTY_OUTSET = new Rect(); - private static final Rect RESIZE_HANDLE_OUTSET = new Rect( - RESIZE_HANDLE_IN_DIP, RESIZE_HANDLE_IN_DIP, RESIZE_HANDLE_IN_DIP, RESIZE_HANDLE_IN_DIP); - private final Handler mHandler; private final Choreographer mChoreographer; private final SyncTransactionQueue mSyncQueue; @@ -69,6 +52,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL private DragResizeInputListener mDragResizeListener; + private RelayoutParams mRelayoutParams = new RelayoutParams(); private final WindowDecoration.RelayoutResult<WindowDecorLinearLayout> mResult = new WindowDecoration.RelayoutResult<>(); @@ -114,19 +98,31 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL void relayout(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) { - final int shadowRadiusDp = taskInfo.isFocused - ? DECOR_SHADOW_FOCUSED_THICKNESS_IN_DIP : DECOR_SHADOW_UNFOCUSED_THICKNESS_IN_DIP; + final int shadowRadiusID = taskInfo.isFocused + ? R.dimen.freeform_decor_shadow_focused_thickness + : R.dimen.freeform_decor_shadow_unfocused_thickness; final boolean isFreeform = mTaskInfo.configuration.windowConfiguration.getWindowingMode() == WindowConfiguration.WINDOWING_MODE_FREEFORM; final boolean isDragResizeable = isFreeform && mTaskInfo.isResizeable; - final Rect outset = isDragResizeable ? RESIZE_HANDLE_OUTSET : EMPTY_OUTSET; WindowDecorLinearLayout oldRootView = mResult.mRootView; final SurfaceControl oldDecorationSurface = mDecorationContainerSurface; final WindowContainerTransaction wct = new WindowContainerTransaction(); - relayout(taskInfo, R.layout.caption_window_decoration, oldRootView, - DECOR_CAPTION_HEIGHT_IN_DIP, DECOR_CAPTION_WIDTH_IN_DIP, outset, shadowRadiusDp, - startT, finishT, wct, mResult); + + int outsetLeftId = R.dimen.freeform_resize_handle; + int outsetTopId = R.dimen.freeform_resize_handle; + int outsetRightId = R.dimen.freeform_resize_handle; + int outsetBottomId = R.dimen.freeform_resize_handle; + + mRelayoutParams.mRunningTaskInfo = taskInfo; + mRelayoutParams.mLayoutResId = R.layout.caption_window_decoration; + mRelayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_height; + mRelayoutParams.mCaptionWidthId = R.dimen.freeform_decor_caption_width; + mRelayoutParams.mShadowRadiusId = shadowRadiusID; + if (isDragResizeable) { + mRelayoutParams.setOutsets(outsetLeftId, outsetTopId, outsetRightId, outsetBottomId); + } + relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult); mTaskOrganizer.applyTransaction(wct); @@ -167,10 +163,12 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL } int touchSlop = ViewConfiguration.get(mResult.mRootView.getContext()).getScaledTouchSlop(); - + int resize_handle = mResult.mRootView.getResources() + .getDimensionPixelSize(R.dimen.freeform_resize_handle); + int resize_corner = mResult.mRootView.getResources() + .getDimensionPixelSize(R.dimen.freeform_resize_corner); mDragResizeListener.setGeometry( - mResult.mWidth, mResult.mHeight, (int) (mResult.mDensity * RESIZE_HANDLE_IN_DIP), - (int) (mResult.mDensity * RESIZE_CORNER_IN_DIP), touchSlop); + mResult.mWidth, mResult.mHeight, resize_handle, resize_corner, touchSlop); } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java index bf863ea2c7ab..01cab9aae312 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java @@ -19,11 +19,11 @@ package com.android.wm.shell.windowdecor; import android.app.ActivityManager.RunningTaskInfo; import android.content.Context; import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.Color; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; -import android.util.DisplayMetrics; import android.view.Display; import android.view.InsetsState; import android.view.LayoutInflater; @@ -142,15 +142,14 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> */ abstract void relayout(RunningTaskInfo taskInfo); - void relayout(RunningTaskInfo taskInfo, int layoutResId, T rootView, float captionHeightDp, - float captionWidthDp, Rect outsetsDp, float shadowRadiusDp, - SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT, - WindowContainerTransaction wct, RelayoutResult<T> outResult) { + void relayout(RelayoutParams params, SurfaceControl.Transaction startT, + SurfaceControl.Transaction finishT, WindowContainerTransaction wct, T rootView, + RelayoutResult<T> outResult) { outResult.reset(); final Configuration oldTaskConfig = mTaskInfo.getConfiguration(); - if (taskInfo != null) { - mTaskInfo = taskInfo; + if (params.mRunningTaskInfo != null) { + mTaskInfo = params.mRunningTaskInfo; } if (!mTaskInfo.isVisible) { @@ -159,7 +158,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> return; } - if (rootView == null && layoutResId == 0) { + if (rootView == null && params.mLayoutResId == 0) { throw new IllegalArgumentException("layoutResId and rootView can't both be invalid."); } @@ -176,15 +175,15 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> return; } mDecorWindowContext = mContext.createConfigurationContext(taskConfig); - if (layoutResId != 0) { - outResult.mRootView = - (T) LayoutInflater.from(mDecorWindowContext).inflate(layoutResId, null); + if (params.mLayoutResId != 0) { + outResult.mRootView = (T) LayoutInflater.from(mDecorWindowContext) + .inflate(params.mLayoutResId, null); } } if (outResult.mRootView == null) { - outResult.mRootView = - (T) LayoutInflater.from(mDecorWindowContext).inflate(layoutResId, null); + outResult.mRootView = (T) LayoutInflater.from(mDecorWindowContext) + .inflate(params.mLayoutResId , null); } // DecorationContainerSurface @@ -200,18 +199,18 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> } final Rect taskBounds = taskConfig.windowConfiguration.getBounds(); - outResult.mDensity = taskConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE; - final int decorContainerOffsetX = -(int) (outsetsDp.left * outResult.mDensity); - final int decorContainerOffsetY = -(int) (outsetsDp.top * outResult.mDensity); + final int decorContainerOffsetX = -loadResource(params.mOutsetLeftId); + final int decorContainerOffsetY = -loadResource(params.mOutsetTopId); outResult.mWidth = taskBounds.width() - + (int) (outsetsDp.right * outResult.mDensity) + + loadResource(params.mOutsetRightId) - decorContainerOffsetX; outResult.mHeight = taskBounds.height() - + (int) (outsetsDp.bottom * outResult.mDensity) + + loadResource(params.mOutsetBottomId) - decorContainerOffsetY; startT.setPosition( mDecorationContainerSurface, decorContainerOffsetX, decorContainerOffsetY) - .setWindowCrop(mDecorationContainerSurface, outResult.mWidth, outResult.mHeight) + .setWindowCrop(mDecorationContainerSurface, + outResult.mWidth, outResult.mHeight) // TODO(b/244455401): Change the z-order when it's better organized .setLayer(mDecorationContainerSurface, mTaskInfo.numActivities + 1) .show(mDecorationContainerSurface); @@ -226,12 +225,13 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> .build(); } - float shadowRadius = outResult.mDensity * shadowRadiusDp; + float shadowRadius = loadResource(params.mShadowRadiusId); int backgroundColorInt = mTaskInfo.taskDescription.getBackgroundColor(); mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f; mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f; mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f; - startT.setWindowCrop(mTaskBackgroundSurface, taskBounds.width(), taskBounds.height()) + startT.setWindowCrop(mTaskBackgroundSurface, taskBounds.width(), + taskBounds.height()) .setShadowRadius(mTaskBackgroundSurface, shadowRadius) .setColor(mTaskBackgroundSurface, mTmpColor) // TODO(b/244455401): Change the z-order when it's better organized @@ -248,8 +248,8 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> .build(); } - final int captionHeight = (int) Math.ceil(captionHeightDp * outResult.mDensity); - final int captionWidth = (int) Math.ceil(captionWidthDp * outResult.mDensity); + final int captionHeight = loadResource(params.mCaptionHeightId); + final int captionWidth = loadResource(params.mCaptionWidthId); //Prevent caption from going offscreen if task is too high up final int captionYPos = taskBounds.top <= captionHeight / 2 ? 0 : captionHeight / 2; @@ -289,8 +289,10 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> // Caption insets mCaptionInsetsRect.set(taskBounds); - mCaptionInsetsRect.bottom = mCaptionInsetsRect.top + captionHeight - captionYPos; - wct.addRectInsetsProvider(mTaskInfo.token, mCaptionInsetsRect, CAPTION_INSETS_TYPES); + mCaptionInsetsRect.bottom = + mCaptionInsetsRect.top + captionHeight - captionYPos; + wct.addRectInsetsProvider(mTaskInfo.token, mCaptionInsetsRect, + CAPTION_INSETS_TYPES); } else { startT.hide(mCaptionContainerSurface); } @@ -307,6 +309,13 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> .setCrop(mTaskSurface, mTaskSurfaceCrop); } + private int loadResource(int resourceId) { + if (resourceId == Resources.ID_NULL) { + return 0; + } + return mDecorWindowContext.getResources().getDimensionPixelSize(resourceId); + } + /** * Obtains the {@link Display} instance for the display ID in {@link #mTaskInfo} if it exists or * registers {@link #mOnDisplaysChangedListener} if it doesn't. @@ -368,13 +377,11 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> static class RelayoutResult<T extends View & TaskFocusStateConsumer> { int mWidth; int mHeight; - float mDensity; T mRootView; void reset() { mWidth = 0; mHeight = 0; - mDensity = 0; mRootView = null; } } @@ -395,4 +402,37 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> return new SurfaceControlViewHost(c, d, wmm); } } + + static class RelayoutParams{ + RunningTaskInfo mRunningTaskInfo; + int mLayoutResId; + int mCaptionHeightId; + int mCaptionWidthId; + int mShadowRadiusId; + + int mOutsetTopId; + int mOutsetBottomId; + int mOutsetLeftId; + int mOutsetRightId; + + void setOutsets(int leftId, int topId, int rightId, int bottomId) { + mOutsetLeftId = leftId; + mOutsetTopId = topId; + mOutsetRightId = rightId; + mOutsetBottomId = bottomId; + } + + void reset() { + mLayoutResId = Resources.ID_NULL; + mCaptionHeightId = Resources.ID_NULL; + mCaptionWidthId = Resources.ID_NULL; + mShadowRadiusId = Resources.ID_NULL; + + mOutsetTopId = Resources.ID_NULL; + mOutsetBottomId = Resources.ID_NULL; + mOutsetLeftId = Resources.ID_NULL; + mOutsetRightId = Resources.ID_NULL; + } + + } }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java index fa62b9c00fc7..103c8dab17d5 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java @@ -51,6 +51,7 @@ import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; +import com.android.wm.shell.R; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.TestRunningTaskInfoBuilder; @@ -76,13 +77,9 @@ import java.util.function.Supplier; @SmallTest @RunWith(AndroidTestingRunner.class) public class WindowDecorationTests extends ShellTestCase { - private static final int CAPTION_HEIGHT_DP = 32; - private static final int CAPTION_WIDTH_DP = 216; - private static final int SHADOW_RADIUS_DP = 5; private static final Rect TASK_BOUNDS = new Rect(100, 300, 400, 400); private static final Point TASK_POSITION_IN_PARENT = new Point(40, 60); - private final Rect mOutsetsDp = new Rect(); private final WindowDecoration.RelayoutResult<TestView> mRelayoutResult = new WindowDecoration.RelayoutResult<>(); @@ -104,6 +101,7 @@ public class WindowDecorationTests extends ShellTestCase { private final List<SurfaceControl.Builder> mMockSurfaceControlBuilders = new ArrayList<>(); private SurfaceControl.Transaction mMockSurfaceControlStartT; private SurfaceControl.Transaction mMockSurfaceControlFinishT; + private WindowDecoration.RelayoutParams mRelayoutParams = new WindowDecoration.RelayoutParams(); @Before public void setUp() { @@ -147,7 +145,8 @@ public class WindowDecorationTests extends ShellTestCase { // Density is 2. Outsets are (20, 40, 60, 80) px. Shadow radius is 10px. Caption height is // 64px. taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2; - mOutsetsDp.set(10, 20, 30, 40); + mRelayoutParams.setOutsets(R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle, + R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle); final SurfaceControl taskSurface = mock(SurfaceControl.class); final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface); @@ -197,8 +196,13 @@ public class WindowDecorationTests extends ShellTestCase { // Density is 2. Outsets are (20, 40, 60, 80) px. Shadow radius is 10px. Caption height is // 64px. taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2; - mOutsetsDp.set(10, 20, 30, 40); - +// int outsetLeftId = R.dimen.split_divider_bar_width; +// int outsetTopId = R.dimen.gestures_onehanded_drag_threshold; +// int outsetRightId = R.dimen.freeform_resize_handle; +// int outsetBottomId = R.dimen.bubble_dismiss_target_padding_x; +// mRelayoutParams.setOutsets(outsetLeftId, outsetTopId, outsetRightId, outsetBottomId); + mRelayoutParams.setOutsets(R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle, + R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle); final SurfaceControl taskSurface = mock(SurfaceControl.class); final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface); @@ -207,8 +211,8 @@ public class WindowDecorationTests extends ShellTestCase { verify(decorContainerSurfaceBuilder).setParent(taskSurface); verify(decorContainerSurfaceBuilder).setContainerLayer(); verify(mMockSurfaceControlStartT).setTrustedOverlay(decorContainerSurface, true); - verify(mMockSurfaceControlStartT).setPosition(decorContainerSurface, -20, -40); - verify(mMockSurfaceControlStartT).setWindowCrop(decorContainerSurface, 380, 220); + verify(mMockSurfaceControlStartT).setPosition(decorContainerSurface, -60, -60); + verify(mMockSurfaceControlStartT).setWindowCrop(decorContainerSurface, 420, 220); verify(taskBackgroundSurfaceBuilder).setParent(taskSurface); verify(taskBackgroundSurfaceBuilder).setEffectLayer(); @@ -221,34 +225,36 @@ public class WindowDecorationTests extends ShellTestCase { verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface); verify(captionContainerSurfaceBuilder).setContainerLayer(); - verify(mMockSurfaceControlStartT).setPosition(captionContainerSurface, -46, 8); - verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64); + verify(mMockSurfaceControlStartT).setPosition(captionContainerSurface, -6, -156); + verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 432); verify(mMockSurfaceControlStartT).show(captionContainerSurface); verify(mMockSurfaceControlViewHostFactory).create(any(), eq(defaultDisplay), any()); + verify(mMockSurfaceControlViewHost) .setView(same(mMockView), - argThat(lp -> lp.height == 64 - && lp.width == 300 + argThat(lp -> lp.height == 432 + && lp.width == 432 && (lp.flags & LayoutParams.FLAG_NOT_FOCUSABLE) != 0)); if (ViewRootImpl.CAPTION_ON_SHELL) { verify(mMockView).setTaskFocusState(true); verify(mMockWindowContainerTransaction) .addRectInsetsProvider(taskInfo.token, - new Rect(100, 300, 400, 364), + new Rect(100, 300, 400, 516), new int[] { InsetsState.ITYPE_CAPTION_BAR }); } verify(mMockSurfaceControlFinishT) .setPosition(taskSurface, TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y); verify(mMockSurfaceControlFinishT) - .setCrop(taskSurface, new Rect(-20, -40, 360, 180)); + .setCrop(taskSurface, new Rect(-60, -60, 360, 160)); verify(mMockSurfaceControlStartT) .show(taskSurface); - assertEquals(380, mRelayoutResult.mWidth); + assertEquals(420, mRelayoutResult.mWidth); assertEquals(220, mRelayoutResult.mHeight); - assertEquals(2, mRelayoutResult.mDensity, 0.f); + + } @Test @@ -287,7 +293,8 @@ public class WindowDecorationTests extends ShellTestCase { // Density is 2. Outsets are (20, 40, 60, 80) px. Shadow radius is 10px. Caption height is // 64px. taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2; - mOutsetsDp.set(10, 20, 30, 40); + mRelayoutParams.setOutsets(R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle, + R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle); final SurfaceControl taskSurface = mock(SurfaceControl.class); final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface); @@ -410,9 +417,15 @@ public class WindowDecorationTests extends ShellTestCase { @Override void relayout(ActivityManager.RunningTaskInfo taskInfo) { - relayout(null /* taskInfo */, 0 /* layoutResId */, mMockView, CAPTION_HEIGHT_DP, - CAPTION_WIDTH_DP, mOutsetsDp, SHADOW_RADIUS_DP, mMockSurfaceControlStartT, - mMockSurfaceControlFinishT, mMockWindowContainerTransaction, mRelayoutResult); + + mRelayoutParams.mLayoutResId = 0; + mRelayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_width; + mRelayoutParams.mCaptionWidthId = R.dimen.freeform_decor_caption_width; + mRelayoutParams.mShadowRadiusId = + R.dimen.freeform_decor_shadow_unfocused_thickness; + + relayout(mRelayoutParams, mMockSurfaceControlStartT, mMockSurfaceControlFinishT, + mMockWindowContainerTransaction, mMockView, mRelayoutResult); } } } diff --git a/media/java/android/media/MediaCrypto.java b/media/java/android/media/MediaCrypto.java index 889a5f7efbb2..1930262ea253 100644 --- a/media/java/android/media/MediaCrypto.java +++ b/media/java/android/media/MediaCrypto.java @@ -75,14 +75,17 @@ public final class MediaCrypto { public final native boolean requiresSecureDecoderComponent(@NonNull String mime); /** - * Associate a MediaDrm session with this MediaCrypto instance. The - * MediaDrm session is used to securely load decryption keys for a - * crypto scheme. The crypto keys loaded through the MediaDrm session + * Associate a new MediaDrm session with this MediaCrypto instance. + * + * <p>The MediaDrm session is used to securely load decryption keys for a + * crypto scheme. The crypto keys loaded through the MediaDrm session * may be selected for use during the decryption operation performed * by {@link android.media.MediaCodec#queueSecureInputBuffer} by specifying - * their key ids in the {@link android.media.MediaCodec.CryptoInfo#key} field. - * @param sessionId the MediaDrm sessionId to associate with this - * MediaCrypto instance + * their key IDs in the {@link android.media.MediaCodec.CryptoInfo#key} field. + * + * @param sessionId The MediaDrm sessionId to associate with this MediaCrypto + * instance. The session's scheme must match the scheme UUID used when + * constructing this MediaCrypto instance. * @throws MediaCryptoException on failure to set the sessionId */ public final native void setMediaDrmSession(@NonNull byte[] sessionId) diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java index 57815370e2ba..681e1124d0ab 100644 --- a/media/java/android/media/MediaRoute2Info.java +++ b/media/java/android/media/MediaRoute2Info.java @@ -539,9 +539,9 @@ public final class MediaRoute2Info implements Parcelable { } /** - * Gets the Deduplication ID of the route if available. - * @see RouteDiscoveryPreference#shouldRemoveDuplicates() - * @hide + * Gets the deduplication IDs associated to the route. + * + * <p>Two routes with a matching deduplication ID originate from the same receiver device. */ @NonNull public Set<String> getDeduplicationIds() { @@ -1017,13 +1017,7 @@ public final class MediaRoute2Info implements Parcelable { } /** - * Sets the deduplication ID of the route. - * Routes have the same ID could be removed even when - * they are from different providers. - * <p> - * If it's {@code null}, the route will not be removed. - * @see RouteDiscoveryPreference#shouldRemoveDuplicates() - * @hide + * Sets the {@link MediaRoute2Info#getDeduplicationIds() deduplication IDs} of the route. */ @NonNull public Builder setDeduplicationIds(@NonNull Set<String> id) { diff --git a/packages/CredentialManager/res/values/strings.xml b/packages/CredentialManager/res/values/strings.xml index 2c24bf14117a..92ce77282cb9 100644 --- a/packages/CredentialManager/res/values/strings.xml +++ b/packages/CredentialManager/res/values/strings.xml @@ -1,4 +1,5 @@ -<resources> +<?xml version="1.0" encoding="utf-8"?> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_name">CredentialManager</string> <string name="string_cancel">Cancel</string> <string name="string_continue">Continue</string> @@ -12,4 +13,7 @@ <string name="choose_create_option_title">Create a passkey at</string> <string name="choose_sign_in_title">Use saved sign in</string> <string name="create_passkey_at">Create passkey at</string> + <string name="use_provider_for_all_title">Use <xliff:g id="providerInfoName">%1$s</xliff:g> for all your sign-ins?</string> + <string name="set_as_default">Set as default</string> + <string name="use_once">Use once</string> </resources>
\ No newline at end of file diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt index 489cc2791370..b63f3c958e1a 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt @@ -21,6 +21,7 @@ import android.app.slice.Slice import android.app.slice.SliceSpec import android.content.Context import android.content.Intent +import android.credentials.ui.Constants import android.credentials.ui.Entry import android.credentials.ui.ProviderData import android.credentials.ui.RequestInfo @@ -60,7 +61,7 @@ class CredentialManagerRepo( ) ?: testProviderList() resultReceiver = intent.getParcelableExtra( - RequestInfo.EXTRA_RESULT_RECEIVER, + Constants.EXTRA_RESULT_RECEIVER, ResultReceiver::class.java ) } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt index f4d60b5f77cc..82fce9f7a98d 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt @@ -83,6 +83,8 @@ fun CreatePasskeyScreen( onOptionSelected = {viewModel.onMoreOptionsRowSelected(it)} ) CreateScreenState.MORE_OPTIONS_ROW_INTRO -> MoreOptionsRowIntroCard( + providerInfo = uiState.selectedProvider!!, + onDefaultOrNotSelected = {viewModel.onDefaultOrNotSelected(it)} ) } }, @@ -282,10 +284,37 @@ fun MoreOptionsSelectionCard( @ExperimentalMaterialApi @Composable fun MoreOptionsRowIntroCard( + providerInfo: ProviderInfo, + onDefaultOrNotSelected: (String) -> Unit, ) { Card( backgroundColor = lightBackgroundColor, ) { + Column() { + Text( + text = stringResource(R.string.use_provider_for_all_title, providerInfo.name), + style = Typography.subtitle1, + modifier = Modifier.padding(all = 24.dp).align(alignment = Alignment.CenterHorizontally) + ) + Row( + horizontalArrangement = Arrangement.SpaceBetween, + modifier = Modifier.fillMaxWidth().padding(horizontal = 24.dp) + ) { + CancelButton( + stringResource(R.string.use_once), + onclick = { onDefaultOrNotSelected(providerInfo.name) } + ) + ConfirmButton( + stringResource(R.string.set_as_default), + onclick = { onDefaultOrNotSelected(providerInfo.name) } + ) + } + Divider( + thickness = 18.dp, + color = Color.Transparent, + modifier = Modifier.padding(bottom = 40.dp) + ) + } } } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt index 3cf81da1fbaa..ff44e2ee1b06 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt @@ -112,4 +112,12 @@ class CreatePasskeyViewModel( CredentialManagerRepo.getInstance().onCancel() dialogResult.value = DialogResult(ResultState.CANCELED) } + + fun onDefaultOrNotSelected(providerName: String) { + uiState = uiState.copy( + currentScreenState = CreateScreenState.CREATION_OPTION_SELECTION, + selectedProvider = getProviderInfoByName(providerName) + ) + // TODO: implement the if choose as default or not logic later + } } diff --git a/packages/SettingsLib/Spa/build.gradle b/packages/SettingsLib/Spa/build.gradle index 811cdd804f8b..68c63dad6726 100644 --- a/packages/SettingsLib/Spa/build.gradle +++ b/packages/SettingsLib/Spa/build.gradle @@ -17,6 +17,7 @@ buildscript { ext { spa_min_sdk = 21 + spa_target_sdk = 33 jetpack_compose_version = '1.2.0-alpha04' jetpack_compose_compiler_version = '1.3.2' jetpack_compose_material3_version = '1.0.0-alpha06' diff --git a/packages/SettingsLib/Spa/gallery/AndroidManifest.xml b/packages/SettingsLib/Spa/gallery/AndroidManifest.xml index 0a4972fac1bb..f1a24aff4319 100644 --- a/packages/SettingsLib/Spa/gallery/AndroidManifest.xml +++ b/packages/SettingsLib/Spa/gallery/AndroidManifest.xml @@ -17,6 +17,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.settingslib.spa.gallery"> + <uses-sdk android:minSdkVersion="21"/> + <application android:name=".GalleryApplication" android:icon="@mipmap/ic_launcher" @@ -32,14 +34,24 @@ </intent-filter> </activity> + <provider + android:name=".GalleryEntryProvider" + android:authorities="com.android.spa.gallery.provider" + android:enabled="true" + android:exported="false"> + </provider> + <activity - android:name=".GalleryDebugActivity" + android:name="com.android.settingslib.spa.framework.debug.BlankActivity" + android:exported="true"> + </activity> + <activity + android:name="com.android.settingslib.spa.framework.debug.DebugActivity" android:exported="true"> </activity> - <provider - android:name=".GalleryEntryProvider" - android:authorities="com.android.spa.gallery.provider" + android:name="com.android.settingslib.spa.framework.debug.DebugProvider" + android:authorities="com.android.spa.gallery.debug" android:enabled="true" android:exported="false"> </provider> diff --git a/packages/SettingsLib/Spa/gallery/build.gradle b/packages/SettingsLib/Spa/gallery/build.gradle index 551a0b107e3a..c1ce7d96702d 100644 --- a/packages/SettingsLib/Spa/gallery/build.gradle +++ b/packages/SettingsLib/Spa/gallery/build.gradle @@ -21,12 +21,12 @@ plugins { android { namespace 'com.android.settingslib.spa.gallery' - compileSdk 33 + compileSdk spa_target_sdk defaultConfig { applicationId "com.android.settingslib.spa.gallery" minSdk spa_min_sdk - targetSdk 33 + targetSdk spa_target_sdk versionCode 1 versionName "1.0" } diff --git a/packages/SettingsLib/Spa/spa/AndroidManifest.xml b/packages/SettingsLib/Spa/spa/AndroidManifest.xml index 410bcdb36782..62800bd34217 100644 --- a/packages/SettingsLib/Spa/spa/AndroidManifest.xml +++ b/packages/SettingsLib/Spa/spa/AndroidManifest.xml @@ -14,4 +14,7 @@ limitations under the License. --> -<manifest package="com.android.settingslib.spa" /> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.settingslib.spa"> + <uses-sdk android:minSdkVersion="21"/> +</manifest> diff --git a/packages/SettingsLib/Spa/spa/build.gradle b/packages/SettingsLib/Spa/spa/build.gradle index 7e05e75804a7..c5874113ef32 100644 --- a/packages/SettingsLib/Spa/spa/build.gradle +++ b/packages/SettingsLib/Spa/spa/build.gradle @@ -21,11 +21,11 @@ plugins { android { namespace 'com.android.settingslib.spa' - compileSdk 33 + compileSdk spa_target_sdk defaultConfig { minSdk spa_min_sdk - targetSdk 33 + targetSdk spa_target_sdk } sourceSets { diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/EntryProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/EntryProvider.kt index 532f63b67c5d..d6317085e4f9 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/EntryProvider.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/EntryProvider.kt @@ -16,21 +16,22 @@ package com.android.settingslib.spa.framework -import android.content.ComponentName import android.content.ContentProvider import android.content.ContentValues import android.content.Context import android.content.Intent -import android.content.Intent.URI_INTENT_SCHEME import android.content.UriMatcher import android.content.pm.ProviderInfo import android.database.Cursor import android.database.MatrixCursor import android.net.Uri import android.util.Log +import com.android.settingslib.spa.framework.common.ColumnEnum +import com.android.settingslib.spa.framework.common.QueryEnum import com.android.settingslib.spa.framework.common.SettingsEntry -import com.android.settingslib.spa.framework.common.SettingsPage import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory +import com.android.settingslib.spa.framework.common.addUri +import com.android.settingslib.spa.framework.common.getColumns private const val TAG = "EntryProvider" @@ -39,117 +40,15 @@ private const val TAG = "EntryProvider" * One can query the provider result by: * $ adb shell content query --uri content://<AuthorityPath>/<QueryPath> * For gallery, AuthorityPath = com.android.spa.gallery.provider - * For SettingsGoogle, AuthorityPath = com.android.settings.spa.provider + * For Settings, AuthorityPath = com.android.settings.spa.provider * Some examples: - * $ adb shell content query --uri content://<AuthorityPath>/page_debug - * $ adb shell content query --uri content://<AuthorityPath>/entry_debug - * $ adb shell content query --uri content://<AuthorityPath>/page_info - * $ adb shell content query --uri content://<AuthorityPath>/entry_info * $ adb shell content query --uri content://<AuthorityPath>/search_sitemap * $ adb shell content query --uri content://<AuthorityPath>/search_static * $ adb shell content query --uri content://<AuthorityPath>/search_dynamic */ open class EntryProvider : ContentProvider() { private val spaEnvironment get() = SpaEnvironmentFactory.instance - - /** - * Enum to define all column names in provider. - */ - enum class ColumnEnum(val id: String) { - // Columns related to page - PAGE_ID("pageId"), - PAGE_NAME("pageName"), - PAGE_ROUTE("pageRoute"), - PAGE_INTENT_URI("pageIntent"), - PAGE_ENTRY_COUNT("entryCount"), - HAS_RUNTIME_PARAM("hasRuntimeParam"), - PAGE_START_ADB("pageStartAdb"), - - // Columns related to entry - ENTRY_ID("entryId"), - ENTRY_NAME("entryName"), - ENTRY_ROUTE("entryRoute"), - ENTRY_INTENT_URI("entryIntent"), - ENTRY_HIERARCHY_PATH("entryPath"), - ENTRY_START_ADB("entryStartAdb"), - - // Columns related to search - ENTRY_TITLE("entryTitle"), - ENTRY_SEARCH_KEYWORD("entrySearchKw"), - } - - /** - * Enum to define all queries supported in the provider. - */ - enum class QueryEnum( - val queryPath: String, - val queryMatchCode: Int, - val columnNames: List<ColumnEnum> - ) { - // For debug - PAGE_DEBUG_QUERY( - "page_debug", 1, - listOf(ColumnEnum.PAGE_START_ADB) - ), - ENTRY_DEBUG_QUERY( - "entry_debug", 2, - listOf(ColumnEnum.ENTRY_START_ADB) - ), - - // page related queries. - PAGE_INFO_QUERY( - "page_info", 100, - listOf( - ColumnEnum.PAGE_ID, - ColumnEnum.PAGE_NAME, - ColumnEnum.PAGE_ROUTE, - ColumnEnum.PAGE_INTENT_URI, - ColumnEnum.PAGE_ENTRY_COUNT, - ColumnEnum.HAS_RUNTIME_PARAM, - ) - ), - - // entry related queries - ENTRY_INFO_QUERY( - "entry_info", 200, - listOf( - ColumnEnum.ENTRY_ID, - ColumnEnum.ENTRY_NAME, - ColumnEnum.ENTRY_ROUTE, - ColumnEnum.ENTRY_INTENT_URI, - ) - ), - - // Search related queries - SEARCH_SITEMAP_QUERY( - "search_sitemap", 300, - listOf( - ColumnEnum.ENTRY_ID, - ColumnEnum.ENTRY_HIERARCHY_PATH, - ) - ), - SEARCH_STATIC_DATA_QUERY( - "search_static", 301, - listOf( - ColumnEnum.ENTRY_ID, - ColumnEnum.ENTRY_TITLE, - ColumnEnum.ENTRY_SEARCH_KEYWORD, - ) - ), - SEARCH_DYNAMIC_DATA_QUERY( - "search_dynamic", 302, - listOf( - ColumnEnum.ENTRY_ID, - ColumnEnum.ENTRY_TITLE, - ColumnEnum.ENTRY_SEARCH_KEYWORD, - ) - ), - } - private val uriMatcher = UriMatcher(UriMatcher.NO_MATCH) - private fun addUri(authority: String, query: QueryEnum) { - uriMatcher.addURI(authority, query.queryPath, query.queryMatchCode) - } override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int { TODO("Implement this to handle requests to delete one or more rows") @@ -182,13 +81,9 @@ open class EntryProvider : ContentProvider() { override fun attachInfo(context: Context?, info: ProviderInfo?) { if (info != null) { - addUri(info.authority, QueryEnum.PAGE_DEBUG_QUERY) - addUri(info.authority, QueryEnum.ENTRY_DEBUG_QUERY) - addUri(info.authority, QueryEnum.PAGE_INFO_QUERY) - addUri(info.authority, QueryEnum.ENTRY_INFO_QUERY) - addUri(info.authority, QueryEnum.SEARCH_SITEMAP_QUERY) - addUri(info.authority, QueryEnum.SEARCH_STATIC_DATA_QUERY) - addUri(info.authority, QueryEnum.SEARCH_DYNAMIC_DATA_QUERY) + QueryEnum.SEARCH_SITEMAP_QUERY.addUri(uriMatcher, info.authority) + QueryEnum.SEARCH_STATIC_DATA_QUERY.addUri(uriMatcher, info.authority) + QueryEnum.SEARCH_DYNAMIC_DATA_QUERY.addUri(uriMatcher, info.authority) } super.attachInfo(context, info) } @@ -202,10 +97,6 @@ open class EntryProvider : ContentProvider() { ): Cursor? { return try { when (uriMatcher.match(uri)) { - QueryEnum.PAGE_DEBUG_QUERY.queryMatchCode -> queryPageDebug() - QueryEnum.ENTRY_DEBUG_QUERY.queryMatchCode -> queryEntryDebug() - QueryEnum.PAGE_INFO_QUERY.queryMatchCode -> queryPageInfo() - QueryEnum.ENTRY_INFO_QUERY.queryMatchCode -> queryEntryInfo() QueryEnum.SEARCH_SITEMAP_QUERY.queryMatchCode -> querySearchSitemap() QueryEnum.SEARCH_STATIC_DATA_QUERY.queryMatchCode -> querySearchStaticData() QueryEnum.SEARCH_DYNAMIC_DATA_QUERY.queryMatchCode -> querySearchDynamicData() @@ -219,73 +110,18 @@ open class EntryProvider : ContentProvider() { } } - private fun queryPageDebug(): Cursor { - val entryRepository by spaEnvironment.entryRepository - val cursor = MatrixCursor(QueryEnum.PAGE_DEBUG_QUERY.getColumns()) - for (pageWithEntry in entryRepository.getAllPageWithEntry()) { - val command = createBrowsePageAdbCommand(pageWithEntry.page) - if (command != null) { - cursor.newRow().add(ColumnEnum.PAGE_START_ADB.id, command) - } - } - return cursor - } - - private fun queryEntryDebug(): Cursor { - val entryRepository by spaEnvironment.entryRepository - val cursor = MatrixCursor(QueryEnum.ENTRY_DEBUG_QUERY.getColumns()) - for (entry in entryRepository.getAllEntries()) { - val command = createBrowsePageAdbCommand(entry.containerPage(), entry.id) - if (command != null) { - cursor.newRow().add(ColumnEnum.ENTRY_START_ADB.id, command) - } - } - return cursor - } - - private fun queryPageInfo(): Cursor { - val entryRepository by spaEnvironment.entryRepository - val cursor = MatrixCursor(QueryEnum.PAGE_INFO_QUERY.getColumns()) - for (pageWithEntry in entryRepository.getAllPageWithEntry()) { - val page = pageWithEntry.page - cursor.newRow() - .add(ColumnEnum.PAGE_ID.id, page.id) - .add(ColumnEnum.PAGE_NAME.id, page.displayName) - .add(ColumnEnum.PAGE_ROUTE.id, page.buildRoute()) - .add(ColumnEnum.PAGE_ENTRY_COUNT.id, pageWithEntry.entries.size) - .add(ColumnEnum.HAS_RUNTIME_PARAM.id, if (page.hasRuntimeParam()) 1 else 0) - .add( - ColumnEnum.PAGE_INTENT_URI.id, - createBrowsePageIntent(page).toUri(URI_INTENT_SCHEME) - ) - } - return cursor - } - - private fun queryEntryInfo(): Cursor { - val entryRepository by spaEnvironment.entryRepository - val cursor = MatrixCursor(QueryEnum.ENTRY_INFO_QUERY.getColumns()) - for (entry in entryRepository.getAllEntries()) { - cursor.newRow() - .add(ColumnEnum.ENTRY_ID.id, entry.id) - .add(ColumnEnum.ENTRY_NAME.id, entry.displayName) - .add(ColumnEnum.ENTRY_ROUTE.id, entry.containerPage().buildRoute()) - .add( - ColumnEnum.ENTRY_INTENT_URI.id, - createBrowsePageIntent(entry.containerPage(), entry.id).toUri(URI_INTENT_SCHEME) - ) - } - return cursor - } - private fun querySearchSitemap(): Cursor { val entryRepository by spaEnvironment.entryRepository val cursor = MatrixCursor(QueryEnum.SEARCH_SITEMAP_QUERY.getColumns()) for (entry in entryRepository.getAllEntries()) { if (!entry.isAllowSearch) continue + val intent = entry.containerPage() + .createBrowseIntent(context, spaEnvironment.browseActivityClass, entry.id) + ?: Intent() cursor.newRow() .add(ColumnEnum.ENTRY_ID.id, entry.id) .add(ColumnEnum.ENTRY_HIERARCHY_PATH.id, entryRepository.getEntryPath(entry.id)) + .add(ColumnEnum.ENTRY_INTENT_URI.id, intent.toUri(Intent.URI_INTENT_SCHEME)) } return cursor } @@ -321,54 +157,4 @@ open class EntryProvider : ContentProvider() { searchData?.keyword ?: emptyList<String>() ) } - - private fun createBrowsePageIntent(page: SettingsPage, entryId: String? = null): Intent { - if (!isPageBrowsable(page)) return Intent() - return Intent().setComponent(ComponentName(context!!, spaEnvironment.browseActivityClass!!)) - .apply { - putExtra(BrowseActivity.KEY_DESTINATION, page.buildRoute()) - if (entryId != null) { - putExtra(BrowseActivity.KEY_HIGHLIGHT_ENTRY, entryId) - } - } - } - - private fun createBrowsePageAdbCommand(page: SettingsPage, entryId: String? = null): String? { - if (!isPageBrowsable(page)) return null - val packageName = context!!.packageName - val activityName = spaEnvironment.browseActivityClass!!.name.replace(packageName, "") - val destinationParam = " -e ${BrowseActivity.KEY_DESTINATION} ${page.buildRoute()}" - val highlightParam = - if (entryId != null) " -e ${BrowseActivity.KEY_HIGHLIGHT_ENTRY} $entryId" else "" - return "adb shell am start -n $packageName/$activityName$destinationParam$highlightParam" - } - - private fun isPageBrowsable(page: SettingsPage): Boolean { - return context != null && - spaEnvironment.browseActivityClass != null && - !page.hasRuntimeParam() - } -} - -fun EntryProvider.QueryEnum.getColumns(): Array<String> { - return columnNames.map { it.id }.toTypedArray() -} - -fun EntryProvider.QueryEnum.getIndex(name: EntryProvider.ColumnEnum): Int { - return columnNames.indexOf(name) -} - -fun Cursor.getString(query: EntryProvider.QueryEnum, columnName: EntryProvider.ColumnEnum): String { - return this.getString(query.getIndex(columnName)) -} - -fun Cursor.getInt(query: EntryProvider.QueryEnum, columnName: EntryProvider.ColumnEnum): Int { - return this.getInt(query.getIndex(columnName)) -} - -fun Cursor.getBoolean( - query: EntryProvider.QueryEnum, - columnName: EntryProvider.ColumnEnum -): Boolean { - return this.getInt(query.getIndex(columnName)) == 1 } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/ProviderColumn.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/ProviderColumn.kt new file mode 100644 index 000000000000..0707429505c8 --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/ProviderColumn.kt @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2022 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.settingslib.spa.framework.common + +import android.content.UriMatcher + +/** + * Enum to define all column names in provider. + */ +enum class ColumnEnum(val id: String) { + // Columns related to page + PAGE_ID("pageId"), + PAGE_NAME("pageName"), + PAGE_ROUTE("pageRoute"), + PAGE_INTENT_URI("pageIntent"), + PAGE_ENTRY_COUNT("entryCount"), + HAS_RUNTIME_PARAM("hasRuntimeParam"), + PAGE_START_ADB("pageStartAdb"), + + // Columns related to entry + ENTRY_ID("entryId"), + ENTRY_NAME("entryName"), + ENTRY_ROUTE("entryRoute"), + ENTRY_INTENT_URI("entryIntent"), + ENTRY_HIERARCHY_PATH("entryPath"), + ENTRY_START_ADB("entryStartAdb"), + + // Columns related to search + ENTRY_TITLE("entryTitle"), + ENTRY_SEARCH_KEYWORD("entrySearchKw"), +} + +/** + * Enum to define all queries supported in the provider. + */ +enum class QueryEnum( + val queryPath: String, + val queryMatchCode: Int, + val columnNames: List<ColumnEnum> +) { + // For debug + PAGE_DEBUG_QUERY( + "page_debug", 1, + listOf(ColumnEnum.PAGE_START_ADB) + ), + ENTRY_DEBUG_QUERY( + "entry_debug", 2, + listOf(ColumnEnum.ENTRY_START_ADB) + ), + + // page related queries. + PAGE_INFO_QUERY( + "page_info", 100, + listOf( + ColumnEnum.PAGE_ID, + ColumnEnum.PAGE_NAME, + ColumnEnum.PAGE_ROUTE, + ColumnEnum.PAGE_INTENT_URI, + ColumnEnum.PAGE_ENTRY_COUNT, + ColumnEnum.HAS_RUNTIME_PARAM, + ) + ), + + // entry related queries + ENTRY_INFO_QUERY( + "entry_info", 200, + listOf( + ColumnEnum.ENTRY_ID, + ColumnEnum.ENTRY_NAME, + ColumnEnum.ENTRY_ROUTE, + ColumnEnum.ENTRY_INTENT_URI, + ) + ), + + // Search related queries + SEARCH_SITEMAP_QUERY( + "search_sitemap", 300, + listOf( + ColumnEnum.ENTRY_ID, + ColumnEnum.ENTRY_HIERARCHY_PATH, + ColumnEnum.ENTRY_INTENT_URI, + ) + ), + SEARCH_STATIC_DATA_QUERY( + "search_static", 301, + listOf( + ColumnEnum.ENTRY_ID, + ColumnEnum.ENTRY_TITLE, + ColumnEnum.ENTRY_SEARCH_KEYWORD, + ) + ), + SEARCH_DYNAMIC_DATA_QUERY( + "search_dynamic", 302, + listOf( + ColumnEnum.ENTRY_ID, + ColumnEnum.ENTRY_TITLE, + ColumnEnum.ENTRY_SEARCH_KEYWORD, + ) + ), +} + +internal fun QueryEnum.getColumns(): Array<String> { + return columnNames.map { it.id }.toTypedArray() +} + +internal fun QueryEnum.getIndex(name: ColumnEnum): Int { + return columnNames.indexOf(name) +} + +internal fun QueryEnum.addUri(uriMatcher: UriMatcher, authority: String) { + uriMatcher.addURI(authority, queryPath, queryMatchCode) +} diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt index 8f63c47b1a9b..07df96e778c4 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt @@ -16,8 +16,13 @@ package com.android.settingslib.spa.framework.common +import android.app.Activity +import android.content.ComponentName +import android.content.Context +import android.content.Intent import android.os.Bundle import androidx.navigation.NamedNavArgument +import com.android.settingslib.spa.framework.BrowseActivity import com.android.settingslib.spa.framework.util.isRuntimeParam import com.android.settingslib.spa.framework.util.navLink import com.android.settingslib.spa.framework.util.normalize @@ -111,6 +116,41 @@ data class SettingsPage( details = formatDisplayTitle() ) } + + fun createBrowseIntent( + context: Context?, + browseActivityClass: Class<out Activity>?, + entryId: String? = null + ): Intent? { + if (!isBrowsable(context, browseActivityClass)) return null + return Intent().setComponent(ComponentName(context!!, browseActivityClass!!)) + .apply { + putExtra(BrowseActivity.KEY_DESTINATION, buildRoute()) + if (entryId != null) { + putExtra(BrowseActivity.KEY_HIGHLIGHT_ENTRY, entryId) + } + } + } + + fun createBrowseAdbCommand( + context: Context?, + browseActivityClass: Class<out Activity>?, + entryId: String? = null + ): String? { + if (!isBrowsable(context, browseActivityClass)) return null + val packageName = context!!.packageName + val activityName = browseActivityClass!!.name.replace(packageName, "") + val destinationParam = " -e ${BrowseActivity.KEY_DESTINATION} ${buildRoute()}" + val highlightParam = + if (entryId != null) " -e ${BrowseActivity.KEY_HIGHLIGHT_ENTRY} $entryId" else "" + return "adb shell am start -n $packageName/$activityName$destinationParam$highlightParam" + } + + fun isBrowsable(context: Context?, browseActivityClass: Class<out Activity>?): Boolean { + return context != null && + browseActivityClass != null && + !hasRuntimeParam() + } } fun String.toHashId(): String { diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/DebugActivity.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/debug/DebugActivity.kt index 6f968180e243..301508074f30 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/DebugActivity.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/debug/DebugActivity.kt @@ -14,12 +14,9 @@ * limitations under the License. */ -package com.android.settingslib.spa.framework +package com.android.settingslib.spa.framework.debug -import android.content.Intent -import android.net.Uri import android.os.Bundle -import android.util.Log import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.material3.Text @@ -33,8 +30,6 @@ import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import androidx.navigation.navArgument import com.android.settingslib.spa.R -import com.android.settingslib.spa.framework.BrowseActivity.Companion.KEY_DESTINATION -import com.android.settingslib.spa.framework.BrowseActivity.Companion.KEY_HIGHLIGHT_ENTRY import com.android.settingslib.spa.framework.common.LogCategory import com.android.settingslib.spa.framework.common.SettingsEntry import com.android.settingslib.spa.framework.common.SettingsPage @@ -60,11 +55,10 @@ private const val PARAM_NAME_ENTRY_ID = "eid" /** * The Debug Activity to display all Spa Pages & Entries. * One can open the debug activity by: - * $ adb shell am start -n <Activity> - * For gallery, Activity = com.android.settingslib.spa.gallery/.GalleryDebugActivity - * For SettingsGoogle, Activity = com.android.settings/.spa.SpaDebugActivity + * $ adb shell am start -n <Package>/com.android.settingslib.spa.framework.debug.DebugActivity + * For gallery, Package = com.android.settingslib.spa.gallery */ -open class DebugActivity : ComponentActivity() { +class DebugActivity : ComponentActivity() { private val spaEnvironment get() = SpaEnvironmentFactory.instance override fun onCreate(savedInstanceState: Bundle?) { @@ -79,30 +73,6 @@ open class DebugActivity : ComponentActivity() { } } - private fun displayDebugMessage() { - val entryProviderAuthorities = spaEnvironment.entryProviderAuthorities ?: return - - try { - val query = EntryProvider.QueryEnum.PAGE_INFO_QUERY - contentResolver.query( - Uri.parse("content://$entryProviderAuthorities/${query.queryPath}"), - null, null, null - ).use { cursor -> - while (cursor != null && cursor.moveToNext()) { - val route = cursor.getString(query, EntryProvider.ColumnEnum.PAGE_ROUTE) - val entryCount = cursor.getInt(query, EntryProvider.ColumnEnum.PAGE_ENTRY_COUNT) - val hasRuntimeParam = - cursor.getBoolean(query, EntryProvider.ColumnEnum.HAS_RUNTIME_PARAM) - val message = "Page Info: $route ($entryCount) " + - (if (hasRuntimeParam) "with" else "no") + "-runtime-params" - spaEnvironment.logger.message(TAG, message, category = LogCategory.FRAMEWORK) - } - } - } catch (e: Exception) { - Log.e(TAG, "Provider querying exception:", e) - } - } - @Composable private fun MainContent() { val navController = rememberNavController() @@ -141,11 +111,6 @@ open class DebugActivity : ComponentActivity() { override val title = "List All Entries (${allEntry.size})" override val onClick = navigator(route = ROUTE_All_ENTRIES) }) - Preference(object : PreferenceModel { - override val title = "Query EntryProvider" - override val enabled = isEntryProviderAvailable().toState() - override val onClick = { displayDebugMessage() } - }) } } @@ -177,6 +142,7 @@ open class DebugActivity : ComponentActivity() { @Composable fun OnePage(arguments: Bundle?) { + val context = LocalContext.current val entryRepository by spaEnvironment.entryRepository val id = arguments!!.getString(PARAM_NAME_PAGE_ID, "") val pageWithEntry = entryRepository.getPageWithEntry(id)!! @@ -186,7 +152,9 @@ open class DebugActivity : ComponentActivity() { Text(text = "Entry size: ${pageWithEntry.entries.size}") Preference(model = object : PreferenceModel { override val title = "open page" - override val enabled = isPageClickable(pageWithEntry.page).toState() + override val enabled = + pageWithEntry.page.isBrowsable(context, spaEnvironment.browseActivityClass) + .toState() override val onClick = openPage(pageWithEntry.page) }) EntryList(pageWithEntry.entries) @@ -195,6 +163,7 @@ open class DebugActivity : ComponentActivity() { @Composable fun OneEntry(arguments: Bundle?) { + val context = LocalContext.current val entryRepository by spaEnvironment.entryRepository val id = arguments!!.getString(PARAM_NAME_ENTRY_ID, "") val entry = entryRepository.getEntry(id)!! @@ -202,7 +171,9 @@ open class DebugActivity : ComponentActivity() { RegularScaffold(title = "Entry - ${entry.displayTitle()}") { Preference(model = object : PreferenceModel { override val title = "open entry" - override val enabled = isEntryClickable(entry).toState() + override val enabled = + entry.containerPage().isBrowsable(context, spaEnvironment.browseActivityClass) + .toState() override val onClick = openEntry(entry) }) Text(text = entryContent) @@ -223,12 +194,10 @@ open class DebugActivity : ComponentActivity() { @Composable private fun openPage(page: SettingsPage): (() -> Unit)? { - if (!isPageClickable(page)) return null val context = LocalContext.current + val intent = + page.createBrowseIntent(context, spaEnvironment.browseActivityClass) ?: return null val route = page.buildRoute() - val intent = Intent(context, spaEnvironment.browseActivityClass).apply { - putExtra(KEY_DESTINATION, route) - } return { spaEnvironment.logger.message( TAG, "OpenPage: $route", category = LogCategory.FRAMEWORK @@ -239,13 +208,11 @@ open class DebugActivity : ComponentActivity() { @Composable private fun openEntry(entry: SettingsEntry): (() -> Unit)? { - if (!isEntryClickable(entry)) return null val context = LocalContext.current + val intent = entry.containerPage() + .createBrowseIntent(context, spaEnvironment.browseActivityClass, entry.id) + ?: return null val route = entry.containerPage().buildRoute() - val intent = Intent(context, spaEnvironment.browseActivityClass).apply { - putExtra(KEY_DESTINATION, route) - putExtra(KEY_HIGHLIGHT_ENTRY, entry.id) - } return { spaEnvironment.logger.message( TAG, "OpenEntry: $route", category = LogCategory.FRAMEWORK @@ -253,17 +220,9 @@ open class DebugActivity : ComponentActivity() { context.startActivity(intent) } } - - private fun isEntryProviderAvailable(): Boolean { - return spaEnvironment.entryProviderAuthorities != null - } - - private fun isPageClickable(page: SettingsPage): Boolean { - return spaEnvironment.browseActivityClass != null && !page.hasRuntimeParam() - } - - private fun isEntryClickable(entry: SettingsEntry): Boolean { - return spaEnvironment.browseActivityClass != null && - !entry.containerPage().hasRuntimeParam() - } } + +/** + * A blank activity without any page. + */ +class BlankActivity : ComponentActivity() diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/debug/DebugProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/debug/DebugProvider.kt new file mode 100644 index 000000000000..6c271094de9f --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/debug/DebugProvider.kt @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2022 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.settingslib.spa.framework.debug + +import android.content.ContentProvider +import android.content.ContentValues +import android.content.Context +import android.content.Intent +import android.content.Intent.URI_INTENT_SCHEME +import android.content.UriMatcher +import android.content.pm.ProviderInfo +import android.database.Cursor +import android.database.MatrixCursor +import android.net.Uri +import android.util.Log +import com.android.settingslib.spa.framework.common.ColumnEnum +import com.android.settingslib.spa.framework.common.QueryEnum +import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory +import com.android.settingslib.spa.framework.common.addUri +import com.android.settingslib.spa.framework.common.getColumns + +private const val TAG = "DebugProvider" + +/** + * The content provider to return debug data. + * One can query the provider result by: + * $ adb shell content query --uri content://<AuthorityPath>/<QueryPath> + * For gallery, AuthorityPath = com.android.spa.gallery.debug + * Some examples: + * $ adb shell content query --uri content://<AuthorityPath>/page_debug + * $ adb shell content query --uri content://<AuthorityPath>/entry_debug + * $ adb shell content query --uri content://<AuthorityPath>/page_info + * $ adb shell content query --uri content://<AuthorityPath>/entry_info + */ +class DebugProvider : ContentProvider() { + private val spaEnvironment get() = SpaEnvironmentFactory.instance + private val uriMatcher = UriMatcher(UriMatcher.NO_MATCH) + + override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int { + TODO("Implement this to handle requests to delete one or more rows") + } + + override fun getType(uri: Uri): String? { + TODO( + "Implement this to handle requests for the MIME type of the data" + + "at the given URI" + ) + } + + override fun insert(uri: Uri, values: ContentValues?): Uri? { + TODO("Implement this to handle requests to insert a new row.") + } + + override fun update( + uri: Uri, + values: ContentValues?, + selection: String?, + selectionArgs: Array<String>? + ): Int { + TODO("Implement this to handle requests to update one or more rows.") + } + + override fun onCreate(): Boolean { + Log.d(TAG, "onCreate") + return true + } + + override fun attachInfo(context: Context?, info: ProviderInfo?) { + if (info != null) { + QueryEnum.PAGE_DEBUG_QUERY.addUri(uriMatcher, info.authority) + QueryEnum.ENTRY_DEBUG_QUERY.addUri(uriMatcher, info.authority) + QueryEnum.PAGE_INFO_QUERY.addUri(uriMatcher, info.authority) + QueryEnum.ENTRY_INFO_QUERY.addUri(uriMatcher, info.authority) + } + super.attachInfo(context, info) + } + + override fun query( + uri: Uri, + projection: Array<String>?, + selection: String?, + selectionArgs: Array<String>?, + sortOrder: String? + ): Cursor? { + return try { + when (uriMatcher.match(uri)) { + QueryEnum.PAGE_DEBUG_QUERY.queryMatchCode -> queryPageDebug() + QueryEnum.ENTRY_DEBUG_QUERY.queryMatchCode -> queryEntryDebug() + QueryEnum.PAGE_INFO_QUERY.queryMatchCode -> queryPageInfo() + QueryEnum.ENTRY_INFO_QUERY.queryMatchCode -> queryEntryInfo() + else -> throw UnsupportedOperationException("Unknown Uri $uri") + } + } catch (e: UnsupportedOperationException) { + throw e + } catch (e: Exception) { + Log.e(TAG, "Provider querying exception:", e) + null + } + } + + private fun queryPageDebug(): Cursor { + val entryRepository by spaEnvironment.entryRepository + val cursor = MatrixCursor(QueryEnum.PAGE_DEBUG_QUERY.getColumns()) + for (pageWithEntry in entryRepository.getAllPageWithEntry()) { + val command = pageWithEntry.page.createBrowseAdbCommand( + context, + spaEnvironment.browseActivityClass + ) + if (command != null) { + cursor.newRow().add(ColumnEnum.PAGE_START_ADB.id, command) + } + } + return cursor + } + + private fun queryEntryDebug(): Cursor { + val entryRepository by spaEnvironment.entryRepository + val cursor = MatrixCursor(QueryEnum.ENTRY_DEBUG_QUERY.getColumns()) + for (entry in entryRepository.getAllEntries()) { + val command = entry.containerPage() + .createBrowseAdbCommand(context, spaEnvironment.browseActivityClass, entry.id) + if (command != null) { + cursor.newRow().add(ColumnEnum.ENTRY_START_ADB.id, command) + } + } + return cursor + } + + private fun queryPageInfo(): Cursor { + val entryRepository by spaEnvironment.entryRepository + val cursor = MatrixCursor(QueryEnum.PAGE_INFO_QUERY.getColumns()) + for (pageWithEntry in entryRepository.getAllPageWithEntry()) { + val page = pageWithEntry.page + val intent = + page.createBrowseIntent(context, spaEnvironment.browseActivityClass) ?: Intent() + cursor.newRow() + .add(ColumnEnum.PAGE_ID.id, page.id) + .add(ColumnEnum.PAGE_NAME.id, page.displayName) + .add(ColumnEnum.PAGE_ROUTE.id, page.buildRoute()) + .add(ColumnEnum.PAGE_ENTRY_COUNT.id, pageWithEntry.entries.size) + .add(ColumnEnum.HAS_RUNTIME_PARAM.id, if (page.hasRuntimeParam()) 1 else 0) + .add(ColumnEnum.PAGE_INTENT_URI.id, intent.toUri(URI_INTENT_SCHEME)) + } + return cursor + } + + private fun queryEntryInfo(): Cursor { + val entryRepository by spaEnvironment.entryRepository + val cursor = MatrixCursor(QueryEnum.ENTRY_INFO_QUERY.getColumns()) + for (entry in entryRepository.getAllEntries()) { + val intent = entry.containerPage() + .createBrowseIntent(context, spaEnvironment.browseActivityClass, entry.id) + ?: Intent() + cursor.newRow() + .add(ColumnEnum.ENTRY_ID.id, entry.id) + .add(ColumnEnum.ENTRY_NAME.id, entry.displayName) + .add(ColumnEnum.ENTRY_ROUTE.id, entry.containerPage().buildRoute()) + .add(ColumnEnum.ENTRY_INTENT_URI.id, intent.toUri(URI_INTENT_SCHEME)) + } + return cursor + } +} diff --git a/packages/SettingsLib/Spa/tests/Android.bp b/packages/SettingsLib/Spa/tests/Android.bp index 1ce49fa520b9..74910456471e 100644 --- a/packages/SettingsLib/Spa/tests/Android.bp +++ b/packages/SettingsLib/Spa/tests/Android.bp @@ -34,4 +34,5 @@ android_test { "truth-prebuilt", ], kotlincflags: ["-Xjvm-default=all"], + min_sdk_version: "31", } diff --git a/packages/SettingsLib/Spa/tests/AndroidManifest.xml b/packages/SettingsLib/Spa/tests/AndroidManifest.xml index c224cafa4740..e2db5943ae53 100644 --- a/packages/SettingsLib/Spa/tests/AndroidManifest.xml +++ b/packages/SettingsLib/Spa/tests/AndroidManifest.xml @@ -17,6 +17,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.settingslib.spa.tests"> + <uses-sdk android:minSdkVersion="21"/> + <application> <uses-library android:name="android.test.runner" /> </application> diff --git a/packages/SettingsLib/Spa/tests/build.gradle b/packages/SettingsLib/Spa/tests/build.gradle index f950e01b9740..b43bf1854c26 100644 --- a/packages/SettingsLib/Spa/tests/build.gradle +++ b/packages/SettingsLib/Spa/tests/build.gradle @@ -21,11 +21,11 @@ plugins { android { namespace 'com.android.settingslib.spa.tests' - compileSdk 33 + compileSdk spa_target_sdk defaultConfig { minSdk spa_min_sdk - targetSdk 33 + targetSdk spa_target_sdk testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/packages/SystemUI/plugin/Android.bp b/packages/SystemUI/plugin/Android.bp index cafaaf854eed..7709f210f22f 100644 --- a/packages/SystemUI/plugin/Android.bp +++ b/packages/SystemUI/plugin/Android.bp @@ -33,6 +33,7 @@ java_library { static_libs: [ "androidx.annotation_annotation", + "error_prone_annotations", "PluginCoreLib", "SystemUIAnimationLib", ], diff --git a/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt index 6124e10144f2..6436dcb5f613 100644 --- a/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt @@ -14,12 +14,11 @@ * limitations under the License. */ -package com.android.systemui.log +package com.android.systemui.plugins.log import android.os.Trace import android.util.Log -import com.android.systemui.log.dagger.LogModule -import com.android.systemui.util.collection.RingBuffer +import com.android.systemui.plugins.util.RingBuffer import com.google.errorprone.annotations.CompileTimeConstant import java.io.PrintWriter import java.util.concurrent.ArrayBlockingQueue @@ -61,15 +60,18 @@ import kotlin.math.max * In either case, `level` can be any of `verbose`, `debug`, `info`, `warn`, `error`, `assert`, or * the first letter of any of the previous. * - * Buffers are provided by [LogModule]. Instances should be created using a [LogBufferFactory]. + * In SystemUI, buffers are provided by LogModule. Instances should be created using a SysUI + * LogBufferFactory. * * @param name The name of this buffer, printed when the buffer is dumped and in some other * situations. * @param maxSize The maximum number of messages to keep in memory at any one time. Buffers start - * out empty and grow up to [maxSize] as new messages are logged. Once the buffer's size reaches - * the maximum, it behaves like a ring buffer. + * out empty and grow up to [maxSize] as new messages are logged. Once the buffer's size reaches the + * maximum, it behaves like a ring buffer. */ -class LogBuffer @JvmOverloads constructor( +class LogBuffer +@JvmOverloads +constructor( private val name: String, private val maxSize: Int, private val logcatEchoTracker: LogcatEchoTracker, @@ -78,7 +80,7 @@ class LogBuffer @JvmOverloads constructor( private val buffer = RingBuffer(maxSize) { LogMessageImpl.create() } private val echoMessageQueue: BlockingQueue<LogMessage>? = - if (logcatEchoTracker.logInBackgroundThread) ArrayBlockingQueue(10) else null + if (logcatEchoTracker.logInBackgroundThread) ArrayBlockingQueue(10) else null init { if (logcatEchoTracker.logInBackgroundThread && echoMessageQueue != null) { @@ -133,11 +135,11 @@ class LogBuffer @JvmOverloads constructor( */ @JvmOverloads inline fun log( - tag: String, - level: LogLevel, - messageInitializer: MessageInitializer, - noinline messagePrinter: MessagePrinter, - exception: Throwable? = null, + tag: String, + level: LogLevel, + messageInitializer: MessageInitializer, + noinline messagePrinter: MessagePrinter, + exception: Throwable? = null, ) { val message = obtain(tag, level, messagePrinter, exception) messageInitializer(message) @@ -152,14 +154,13 @@ class LogBuffer @JvmOverloads constructor( * log message is built during runtime, use the [LogBuffer.log] overloaded method that takes in * an initializer and a message printer. * - * Log buffers are limited by the number of entries, so logging more frequently - * will limit the time window that the LogBuffer covers in a bug report. Richer logs, on the - * other hand, make a bug report more actionable, so using the [log] with a messagePrinter to - * add more detail to every log may do more to improve overall logging than adding more logs - * with this method. + * Log buffers are limited by the number of entries, so logging more frequently will limit the + * time window that the LogBuffer covers in a bug report. Richer logs, on the other hand, make a + * bug report more actionable, so using the [log] with a messagePrinter to add more detail to + * every log may do more to improve overall logging than adding more logs with this method. */ fun log(tag: String, level: LogLevel, @CompileTimeConstant message: String) = - log(tag, level, {str1 = message}, { str1!! }) + log(tag, level, { str1 = message }, { str1!! }) /** * You should call [log] instead of this method. @@ -172,10 +173,10 @@ class LogBuffer @JvmOverloads constructor( */ @Synchronized fun obtain( - tag: String, - level: LogLevel, - messagePrinter: MessagePrinter, - exception: Throwable? = null, + tag: String, + level: LogLevel, + messagePrinter: MessagePrinter, + exception: Throwable? = null, ): LogMessage { if (!mutable) { return FROZEN_MESSAGE @@ -189,8 +190,7 @@ class LogBuffer @JvmOverloads constructor( * You should call [log] instead of this method. * * After acquiring a message via [obtain], call this method to signal to the buffer that you - * have finished filling in its data fields. The message will be echoed to logcat if - * necessary. + * have finished filling in its data fields. The message will be echoed to logcat if necessary. */ @Synchronized fun commit(message: LogMessage) { @@ -213,7 +213,8 @@ class LogBuffer @JvmOverloads constructor( /** Sends message to echo after determining whether to use Logcat and/or systrace. */ private fun echoToDesiredEndpoints(message: LogMessage) { - val includeInLogcat = logcatEchoTracker.isBufferLoggable(name, message.level) || + val includeInLogcat = + logcatEchoTracker.isBufferLoggable(name, message.level) || logcatEchoTracker.isTagLoggable(message.tag, message.level) echo(message, toLogcat = includeInLogcat, toSystrace = systrace) } @@ -221,7 +222,12 @@ class LogBuffer @JvmOverloads constructor( /** Converts the entire buffer to a newline-delimited string */ @Synchronized fun dump(pw: PrintWriter, tailLength: Int) { - val iterationStart = if (tailLength <= 0) { 0 } else { max(0, buffer.size - tailLength) } + val iterationStart = + if (tailLength <= 0) { + 0 + } else { + max(0, buffer.size - tailLength) + } for (i in iterationStart until buffer.size) { buffer[i].dump(pw) @@ -229,9 +235,9 @@ class LogBuffer @JvmOverloads constructor( } /** - * "Freezes" the contents of the buffer, making it immutable until [unfreeze] is called. - * Calls to [log], [obtain], and [commit] will not affect the buffer and will return dummy - * values if necessary. + * "Freezes" the contents of the buffer, making it immutable until [unfreeze] is called. Calls + * to [log], [obtain], and [commit] will not affect the buffer and will return dummy values if + * necessary. */ @Synchronized fun freeze() { @@ -241,9 +247,7 @@ class LogBuffer @JvmOverloads constructor( } } - /** - * Undoes the effects of calling [freeze]. - */ + /** Undoes the effects of calling [freeze]. */ @Synchronized fun unfreeze() { if (frozen) { @@ -265,8 +269,11 @@ class LogBuffer @JvmOverloads constructor( } private fun echoToSystrace(message: LogMessage, strMessage: String) { - Trace.instantForTrack(Trace.TRACE_TAG_APP, "UI Events", - "$name - ${message.level.shortString} ${message.tag}: $strMessage") + Trace.instantForTrack( + Trace.TRACE_TAG_APP, + "UI Events", + "$name - ${message.level.shortString} ${message.tag}: $strMessage" + ) } private fun echoToLogcat(message: LogMessage, strMessage: String) { diff --git a/packages/SystemUI/src/com/android/systemui/log/LogLevel.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogLevel.kt index 53f231c9f9d2..b036cf0be1d6 100644 --- a/packages/SystemUI/src/com/android/systemui/log/LogLevel.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogLevel.kt @@ -14,17 +14,12 @@ * limitations under the License. */ -package com.android.systemui.log +package com.android.systemui.plugins.log import android.util.Log -/** - * Enum version of @Log.Level - */ -enum class LogLevel( - @Log.Level val nativeLevel: Int, - val shortString: String -) { +/** Enum version of @Log.Level */ +enum class LogLevel(@Log.Level val nativeLevel: Int, val shortString: String) { VERBOSE(Log.VERBOSE, "V"), DEBUG(Log.DEBUG, "D"), INFO(Log.INFO, "I"), diff --git a/packages/SystemUI/src/com/android/systemui/log/LogMessage.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogMessage.kt index dae2592e116c..9468681289bf 100644 --- a/packages/SystemUI/src/com/android/systemui/log/LogMessage.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogMessage.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.log +package com.android.systemui.plugins.log import java.io.PrintWriter import java.text.SimpleDateFormat @@ -29,9 +29,10 @@ import java.util.Locale * * When a message is logged, the code doing the logging stores data in one or more of the generic * fields ([str1], [int1], etc). When it comes time to dump the message to logcat/bugreport/etc, the - * [messagePrinter] function reads the data stored in the generic fields and converts that to a human- - * readable string. Thus, for every log type there must be a specialized initializer function that - * stores data specific to that log type and a specialized printer function that prints that data. + * [messagePrinter] function reads the data stored in the generic fields and converts that to a + * human- readable string. Thus, for every log type there must be a specialized initializer function + * that stores data specific to that log type and a specialized printer function that prints that + * data. * * See [LogBuffer.log] for more information. */ @@ -55,9 +56,7 @@ interface LogMessage { var bool3: Boolean var bool4: Boolean - /** - * Function that dumps the [LogMessage] to the provided [writer]. - */ + /** Function that dumps the [LogMessage] to the provided [writer]. */ fun dump(writer: PrintWriter) { val formattedTimestamp = DATE_FORMAT.format(timestamp) val shortLevel = level.shortString @@ -68,12 +67,12 @@ interface LogMessage { } /** - * A function that will be called if and when the message needs to be dumped to - * logcat or a bug report. It should read the data stored by the initializer and convert it to - * a human-readable string. The value of `this` will be the LogMessage to be printed. - * **IMPORTANT:** The printer should ONLY ever reference fields on the LogMessage and NEVER any - * variables in its enclosing scope. Otherwise, the runtime will need to allocate a new instance - * of the printer for each call, thwarting our attempts at avoiding any sort of allocation. + * A function that will be called if and when the message needs to be dumped to logcat or a bug + * report. It should read the data stored by the initializer and convert it to a human-readable + * string. The value of `this` will be the LogMessage to be printed. **IMPORTANT:** The printer + * should ONLY ever reference fields on the LogMessage and NEVER any variables in its enclosing + * scope. Otherwise, the runtime will need to allocate a new instance of the printer for each call, + * thwarting our attempts at avoiding any sort of allocation. */ typealias MessagePrinter = LogMessage.() -> String diff --git a/packages/SystemUI/src/com/android/systemui/log/LogMessageImpl.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogMessageImpl.kt index 4dd6f652d1c7..f2a6a91adcdf 100644 --- a/packages/SystemUI/src/com/android/systemui/log/LogMessageImpl.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogMessageImpl.kt @@ -14,11 +14,9 @@ * limitations under the License. */ -package com.android.systemui.log +package com.android.systemui.plugins.log -/** - * Recyclable implementation of [LogMessage]. - */ +/** Recyclable implementation of [LogMessage]. */ data class LogMessageImpl( override var level: LogLevel, override var tag: String, @@ -68,23 +66,24 @@ data class LogMessageImpl( companion object Factory { fun create(): LogMessageImpl { return LogMessageImpl( - LogLevel.DEBUG, - DEFAULT_TAG, - 0, - DEFAULT_PRINTER, - null, - null, - null, - null, - 0, - 0, - 0, - 0, - 0.0, - false, - false, - false, - false) + LogLevel.DEBUG, + DEFAULT_TAG, + 0, + DEFAULT_PRINTER, + null, + null, + null, + null, + 0, + 0, + 0, + 0, + 0.0, + false, + false, + false, + false + ) } } } diff --git a/packages/SystemUI/src/com/android/systemui/log/LogcatEchoTracker.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTracker.kt index 8cda4236bc87..cfe894f276a0 100644 --- a/packages/SystemUI/src/com/android/systemui/log/LogcatEchoTracker.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTracker.kt @@ -14,24 +14,16 @@ * limitations under the License. */ -package com.android.systemui.log +package com.android.systemui.plugins.log -/** - * Keeps track of which [LogBuffer] messages should also appear in logcat. - */ +/** Keeps track of which [LogBuffer] messages should also appear in logcat. */ interface LogcatEchoTracker { - /** - * Whether [bufferName] should echo messages of [level] or higher to logcat. - */ + /** Whether [bufferName] should echo messages of [level] or higher to logcat. */ fun isBufferLoggable(bufferName: String, level: LogLevel): Boolean - /** - * Whether [tagName] should echo messages of [level] or higher to logcat. - */ + /** Whether [tagName] should echo messages of [level] or higher to logcat. */ fun isTagLoggable(tagName: String, level: LogLevel): Boolean - /** - * Whether to log messages in a background thread. - */ + /** Whether to log messages in a background thread. */ val logInBackgroundThread: Boolean } diff --git a/packages/SystemUI/src/com/android/systemui/log/LogcatEchoTrackerDebug.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerDebug.kt index 40b0cdc173d8..d3fabaccb6d3 100644 --- a/packages/SystemUI/src/com/android/systemui/log/LogcatEchoTrackerDebug.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerDebug.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.log +package com.android.systemui.plugins.log import android.content.ContentResolver import android.database.ContentObserver @@ -36,19 +36,15 @@ import android.provider.Settings * $ adb shell settings put global systemui/tag/<tag> <level> * ``` */ -class LogcatEchoTrackerDebug private constructor( - private val contentResolver: ContentResolver -) : LogcatEchoTracker { +class LogcatEchoTrackerDebug private constructor(private val contentResolver: ContentResolver) : + LogcatEchoTracker { private val cachedBufferLevels: MutableMap<String, LogLevel> = mutableMapOf() private val cachedTagLevels: MutableMap<String, LogLevel> = mutableMapOf() override val logInBackgroundThread = true companion object Factory { @JvmStatic - fun create( - contentResolver: ContentResolver, - mainLooper: Looper - ): LogcatEchoTrackerDebug { + fun create(contentResolver: ContentResolver, mainLooper: Looper): LogcatEchoTrackerDebug { val tracker = LogcatEchoTrackerDebug(contentResolver) tracker.attach(mainLooper) return tracker @@ -57,37 +53,35 @@ class LogcatEchoTrackerDebug private constructor( private fun attach(mainLooper: Looper) { contentResolver.registerContentObserver( - Settings.Global.getUriFor(BUFFER_PATH), - true, - object : ContentObserver(Handler(mainLooper)) { - override fun onChange(selfChange: Boolean, uri: Uri?) { - super.onChange(selfChange, uri) - cachedBufferLevels.clear() - } - }) + Settings.Global.getUriFor(BUFFER_PATH), + true, + object : ContentObserver(Handler(mainLooper)) { + override fun onChange(selfChange: Boolean, uri: Uri?) { + super.onChange(selfChange, uri) + cachedBufferLevels.clear() + } + } + ) contentResolver.registerContentObserver( - Settings.Global.getUriFor(TAG_PATH), - true, - object : ContentObserver(Handler(mainLooper)) { - override fun onChange(selfChange: Boolean, uri: Uri?) { - super.onChange(selfChange, uri) - cachedTagLevels.clear() - } - }) + Settings.Global.getUriFor(TAG_PATH), + true, + object : ContentObserver(Handler(mainLooper)) { + override fun onChange(selfChange: Boolean, uri: Uri?) { + super.onChange(selfChange, uri) + cachedTagLevels.clear() + } + } + ) } - /** - * Whether [bufferName] should echo messages of [level] or higher to logcat. - */ + /** Whether [bufferName] should echo messages of [level] or higher to logcat. */ @Synchronized override fun isBufferLoggable(bufferName: String, level: LogLevel): Boolean { return level.ordinal >= getLogLevel(bufferName, BUFFER_PATH, cachedBufferLevels).ordinal } - /** - * Whether [tagName] should echo messages of [level] or higher to logcat. - */ + /** Whether [tagName] should echo messages of [level] or higher to logcat. */ @Synchronized override fun isTagLoggable(tagName: String, level: LogLevel): Boolean { return level >= getLogLevel(tagName, TAG_PATH, cachedTagLevels) diff --git a/packages/SystemUI/src/com/android/systemui/log/LogcatEchoTrackerProd.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerProd.kt index 1a4ad1907ff1..3c8bda4a44e0 100644 --- a/packages/SystemUI/src/com/android/systemui/log/LogcatEchoTrackerProd.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerProd.kt @@ -14,11 +14,9 @@ * limitations under the License. */ -package com.android.systemui.log +package com.android.systemui.plugins.log -/** - * Production version of [LogcatEchoTracker] that isn't configurable. - */ +/** Production version of [LogcatEchoTracker] that isn't configurable. */ class LogcatEchoTrackerProd : LogcatEchoTracker { override val logInBackgroundThread = false diff --git a/packages/SystemUI/src/com/android/systemui/util/collection/RingBuffer.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/util/RingBuffer.kt index 97dc842ec699..68d78907f028 100644 --- a/packages/SystemUI/src/com/android/systemui/util/collection/RingBuffer.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/util/RingBuffer.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.util.collection +package com.android.systemui.plugins.util import kotlin.math.max @@ -32,19 +32,16 @@ import kotlin.math.max * @param factory A function that creates a fresh instance of T. Used by the buffer while it's * growing to [maxSize]. */ -class RingBuffer<T>( - private val maxSize: Int, - private val factory: () -> T -) : Iterable<T> { +class RingBuffer<T>(private val maxSize: Int, private val factory: () -> T) : Iterable<T> { private val buffer = MutableList<T?>(maxSize) { null } /** * An abstract representation that points to the "end" of the buffer. Increments every time - * [advance] is called and never wraps. Use [indexOf] to calculate the associated index into - * the backing array. Always points to the "next" available slot in the buffer. Before the - * buffer has completely filled, the value pointed to will be null. Afterward, it will be the - * value at the "beginning" of the buffer. + * [advance] is called and never wraps. Use [indexOf] to calculate the associated index into the + * backing array. Always points to the "next" available slot in the buffer. Before the buffer + * has completely filled, the value pointed to will be null. Afterward, it will be the value at + * the "beginning" of the buffer. * * This value is unlikely to overflow. Assuming [advance] is called at rate of 100 calls/ms, * omega will overflow after a little under three million years of continuous operation. @@ -60,24 +57,23 @@ class RingBuffer<T>( /** * Advances the buffer's position by one and returns the value that is now present at the "end" - * of the buffer. If the buffer is not yet full, uses [factory] to create a new item. - * Otherwise, reuses the value that was previously at the "beginning" of the buffer. + * of the buffer. If the buffer is not yet full, uses [factory] to create a new item. Otherwise, + * reuses the value that was previously at the "beginning" of the buffer. * - * IMPORTANT: The value is returned as-is, without being reset. It will retain any data that - * was previously stored on it. + * IMPORTANT: The value is returned as-is, without being reset. It will retain any data that was + * previously stored on it. */ fun advance(): T { val index = indexOf(omega) omega += 1 - val entry = buffer[index] ?: factory().also { - buffer[index] = it - } + val entry = buffer[index] ?: factory().also { buffer[index] = it } return entry } /** * Returns the value stored at [index], which can range from 0 (the "start", or oldest element - * of the buffer) to [size] - 1 (the "end", or newest element of the buffer). + * of the buffer) to [size] + * - 1 (the "end", or newest element of the buffer). */ operator fun get(index: Int): T { if (index < 0 || index >= size) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt b/packages/SystemUI/plugin/tests/log/LogBufferTest.kt index 56aff3c2fc8b..a39b856f0f49 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt +++ b/packages/SystemUI/plugin/tests/log/LogBufferTest.kt @@ -2,6 +2,7 @@ package com.android.systemui.log import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.plugins.log.LogBuffer import com.google.common.truth.Truth.assertThat import java.io.PrintWriter import java.io.StringWriter @@ -18,8 +19,7 @@ class LogBufferTest : SysuiTestCase() { private lateinit var outputWriter: StringWriter - @Mock - private lateinit var logcatEchoTracker: LogcatEchoTracker + @Mock private lateinit var logcatEchoTracker: LogcatEchoTracker @Before fun setup() { @@ -67,15 +67,17 @@ class LogBufferTest : SysuiTestCase() { @Test fun dump_writesCauseAndStacktrace() { buffer = createBuffer() - val exception = createTestException("Exception message", + val exception = + createTestException( + "Exception message", "TestClass", - cause = createTestException("The real cause!", "TestClass")) + cause = createTestException("The real cause!", "TestClass") + ) buffer.log("Tag", LogLevel.ERROR, { str1 = "Extra message" }, { str1!! }, exception) val dumpedString = dumpBuffer() - assertThat(dumpedString) - .contains("Caused by: java.lang.RuntimeException: The real cause!") + assertThat(dumpedString).contains("Caused by: java.lang.RuntimeException: The real cause!") assertThat(dumpedString).contains("at TestClass.TestMethod(TestClass.java:1)") assertThat(dumpedString).contains("at TestClass.TestMethod(TestClass.java:2)") } @@ -85,49 +87,47 @@ class LogBufferTest : SysuiTestCase() { buffer = createBuffer() val exception = RuntimeException("Root exception message") exception.addSuppressed( - createTestException( - "First suppressed exception", - "FirstClass", - createTestException("Cause of suppressed exp", "ThirdClass") - )) - exception.addSuppressed( - createTestException("Second suppressed exception", "SecondClass")) + createTestException( + "First suppressed exception", + "FirstClass", + createTestException("Cause of suppressed exp", "ThirdClass") + ) + ) + exception.addSuppressed(createTestException("Second suppressed exception", "SecondClass")) buffer.log("Tag", LogLevel.ERROR, { str1 = "Extra message" }, { str1!! }, exception) val dumpedStr = dumpBuffer() // first suppressed exception assertThat(dumpedStr) - .contains("Suppressed: " + - "java.lang.RuntimeException: First suppressed exception") + .contains("Suppressed: " + "java.lang.RuntimeException: First suppressed exception") assertThat(dumpedStr).contains("at FirstClass.TestMethod(FirstClass.java:1)") assertThat(dumpedStr).contains("at FirstClass.TestMethod(FirstClass.java:2)") assertThat(dumpedStr) - .contains("Caused by: java.lang.RuntimeException: Cause of suppressed exp") + .contains("Caused by: java.lang.RuntimeException: Cause of suppressed exp") assertThat(dumpedStr).contains("at ThirdClass.TestMethod(ThirdClass.java:1)") assertThat(dumpedStr).contains("at ThirdClass.TestMethod(ThirdClass.java:2)") // second suppressed exception assertThat(dumpedStr) - .contains("Suppressed: " + - "java.lang.RuntimeException: Second suppressed exception") + .contains("Suppressed: " + "java.lang.RuntimeException: Second suppressed exception") assertThat(dumpedStr).contains("at SecondClass.TestMethod(SecondClass.java:1)") assertThat(dumpedStr).contains("at SecondClass.TestMethod(SecondClass.java:2)") } private fun createTestException( - message: String, - errorClass: String, - cause: Throwable? = null, + message: String, + errorClass: String, + cause: Throwable? = null, ): Exception { val exception = RuntimeException(message, cause) - exception.stackTrace = (1..5).map { lineNumber -> - StackTraceElement(errorClass, - "TestMethod", - "$errorClass.java", - lineNumber) - }.toTypedArray() + exception.stackTrace = + (1..5) + .map { lineNumber -> + StackTraceElement(errorClass, "TestMethod", "$errorClass.java", lineNumber) + } + .toTypedArray() return exception } diff --git a/packages/SystemUI/res/layout/combined_qs_header.xml b/packages/SystemUI/res/layout/combined_qs_header.xml index 5dc34b9db594..a565988c14ad 100644 --- a/packages/SystemUI/res/layout/combined_qs_header.xml +++ b/packages/SystemUI/res/layout/combined_qs_header.xml @@ -73,8 +73,8 @@ android:singleLine="true" android:textDirection="locale" android:textAppearance="@style/TextAppearance.QS.Status" - android:transformPivotX="0sp" - android:transformPivotY="20sp" + android:transformPivotX="0dp" + android:transformPivotY="24dp" android:scaleX="1" android:scaleY="1" /> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 01c9ac1b9d15..66f0e7543469 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -519,7 +519,7 @@ <dimen name="qs_tile_margin_horizontal">8dp</dimen> <dimen name="qs_tile_margin_vertical">@dimen/qs_tile_margin_horizontal</dimen> <dimen name="qs_tile_margin_top_bottom">4dp</dimen> - <dimen name="qs_brightness_margin_top">8dp</dimen> + <dimen name="qs_brightness_margin_top">12dp</dimen> <dimen name="qs_brightness_margin_bottom">16dp</dimen> <dimen name="qqs_layout_margin_top">16dp</dimen> <dimen name="qqs_layout_padding_bottom">24dp</dimen> @@ -572,6 +572,7 @@ <dimen name="qs_header_row_min_height">48dp</dimen> <dimen name="qs_header_non_clickable_element_height">24dp</dimen> + <dimen name="new_qs_header_non_clickable_element_height">20dp</dimen> <dimen name="qs_footer_padding">20dp</dimen> <dimen name="qs_security_footer_height">88dp</dimen> diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml index 3164ed1e6751..e30d4415a0c4 100644 --- a/packages/SystemUI/res/values/integers.xml +++ b/packages/SystemUI/res/values/integers.xml @@ -28,4 +28,11 @@ <!-- The time it takes for the over scroll release animation to complete, in milli seconds. --> <integer name="lockscreen_shade_over_scroll_release_duration">0</integer> + + <!-- Values for transition of QS Headers --> + <integer name="fade_out_complete_frame">14</integer> + <integer name="fade_in_start_frame">58</integer> + <!-- Percentage of displacement for items in QQS to guarantee matching with bottom of clock at + fade_out_complete_frame --> + <dimen name="percent_displacement_at_fade_out" format="float">0.1066</dimen> </resources>
\ No newline at end of file diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index a734fa744b48..475ca919c3bf 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -128,11 +128,10 @@ <!-- This is hard coded to be sans-serif-condensed to match the icons --> <style name="TextAppearance.QS.Status"> - <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item> + <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> <item name="android:textColor">?android:attr/textColorPrimary</item> <item name="android:textSize">14sp</item> <item name="android:letterSpacing">0.01</item> - <item name="android:lineHeight">20sp</item> </style> <style name="TextAppearance.QS.SecurityFooter" parent="@style/TextAppearance.QS.Status"> @@ -143,12 +142,10 @@ <style name="TextAppearance.QS.Status.Carriers" /> <style name="TextAppearance.QS.Status.Carriers.NoCarrierText"> - <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> <item name="android:textColor">?android:attr/textColorSecondary</item> </style> <style name="TextAppearance.QS.Status.Build"> - <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> <item name="android:textColor">?android:attr/textColorSecondary</item> </style> diff --git a/packages/SystemUI/res/xml/combined_qs_header_scene.xml b/packages/SystemUI/res/xml/combined_qs_header_scene.xml index f3866c08cbfc..de855e275f5f 100644 --- a/packages/SystemUI/res/xml/combined_qs_header_scene.xml +++ b/packages/SystemUI/res/xml/combined_qs_header_scene.xml @@ -27,67 +27,60 @@ <KeyPosition app:keyPositionType="deltaRelative" app:percentX="0" - app:percentY="0" - app:framePosition="49" + app:percentY="@dimen/percent_displacement_at_fade_out" + app:framePosition="@integer/fade_out_complete_frame" app:sizePercent="0" app:curveFit="linear" app:motionTarget="@id/date" /> <KeyPosition app:keyPositionType="deltaRelative" app:percentX="1" - app:percentY="0.51" + app:percentY="0.5" app:sizePercent="1" - app:framePosition="51" + app:framePosition="50" app:curveFit="linear" app:motionTarget="@id/date" /> <KeyAttribute app:motionTarget="@id/date" - app:framePosition="30" + app:framePosition="14" android:alpha="0" /> <KeyAttribute app:motionTarget="@id/date" - app:framePosition="70" + app:framePosition="@integer/fade_in_start_frame" android:alpha="0" /> <KeyPosition - app:keyPositionType="pathRelative" - app:percentX="0" - app:percentY="0" - app:framePosition="0" - app:curveFit="linear" - app:motionTarget="@id/statusIcons" /> - <KeyPosition - app:keyPositionType="pathRelative" + app:keyPositionType="deltaRelative" app:percentX="0" - app:percentY="0" - app:framePosition="50" + app:percentY="@dimen/percent_displacement_at_fade_out" + app:framePosition="@integer/fade_out_complete_frame" app:sizePercent="0" app:curveFit="linear" app:motionTarget="@id/statusIcons" /> <KeyPosition app:keyPositionType="deltaRelative" app:percentX="1" - app:percentY="0.51" - app:framePosition="51" + app:percentY="0.5" + app:framePosition="50" app:sizePercent="1" app:curveFit="linear" app:motionTarget="@id/statusIcons" /> <KeyAttribute app:motionTarget="@id/statusIcons" - app:framePosition="30" + app:framePosition="@integer/fade_out_complete_frame" android:alpha="0" /> <KeyAttribute app:motionTarget="@id/statusIcons" - app:framePosition="70" + app:framePosition="@integer/fade_in_start_frame" android:alpha="0" /> <KeyPosition app:keyPositionType="deltaRelative" app:percentX="0" - app:percentY="0" - app:framePosition="50" + app:percentY="@dimen/percent_displacement_at_fade_out" + app:framePosition="@integer/fade_out_complete_frame" app:percentWidth="1" app:percentHeight="1" app:curveFit="linear" @@ -95,27 +88,27 @@ <KeyPosition app:keyPositionType="deltaRelative" app:percentX="1" - app:percentY="0.51" - app:framePosition="51" + app:percentY="0.5" + app:framePosition="50" app:percentWidth="1" app:percentHeight="1" app:curveFit="linear" app:motionTarget="@id/batteryRemainingIcon" /> <KeyAttribute app:motionTarget="@id/batteryRemainingIcon" - app:framePosition="30" + app:framePosition="@integer/fade_out_complete_frame" android:alpha="0" /> <KeyAttribute app:motionTarget="@id/batteryRemainingIcon" - app:framePosition="70" + app:framePosition="@integer/fade_in_start_frame" android:alpha="0" /> <KeyPosition app:motionTarget="@id/carrier_group" app:percentX="1" - app:percentY="0.51" - app:framePosition="51" + app:percentY="0.5" + app:framePosition="50" app:percentWidth="1" app:percentHeight="1" app:curveFit="linear" @@ -126,7 +119,7 @@ android:alpha="0" /> <KeyAttribute app:motionTarget="@id/carrier_group" - app:framePosition="70" + app:framePosition="@integer/fade_in_start_frame" android:alpha="0" /> </KeyFrameSet> </Transition> diff --git a/packages/SystemUI/res/xml/qqs_header.xml b/packages/SystemUI/res/xml/qqs_header.xml index a82684d0358b..88b4f43b440b 100644 --- a/packages/SystemUI/res/xml/qqs_header.xml +++ b/packages/SystemUI/res/xml/qqs_header.xml @@ -43,7 +43,8 @@ android:id="@+id/date"> <Layout android:layout_width="0dp" - android:layout_height="@dimen/qs_header_non_clickable_element_height" + android:layout_height="@dimen/new_qs_header_non_clickable_element_height" + android:layout_marginStart="8dp" app:layout_constrainedWidth="true" app:layout_constraintStart_toEndOf="@id/clock" app:layout_constraintEnd_toStartOf="@id/barrier" @@ -57,8 +58,8 @@ android:id="@+id/statusIcons"> <Layout android:layout_width="0dp" - android:layout_height="@dimen/qs_header_non_clickable_element_height" - app:layout_constraintHeight_min="@dimen/qs_header_non_clickable_element_height" + android:layout_height="@dimen/new_qs_header_non_clickable_element_height" + app:layout_constraintHeight_min="@dimen/new_qs_header_non_clickable_element_height" app:layout_constraintStart_toEndOf="@id/date" app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon" app:layout_constraintTop_toTopOf="parent" @@ -71,9 +72,9 @@ android:id="@+id/batteryRemainingIcon"> <Layout android:layout_width="wrap_content" - android:layout_height="@dimen/qs_header_non_clickable_element_height" + android:layout_height="@dimen/new_qs_header_non_clickable_element_height" app:layout_constrainedWidth="true" - app:layout_constraintHeight_min="@dimen/qs_header_non_clickable_element_height" + app:layout_constraintHeight_min="@dimen/new_qs_header_non_clickable_element_height" app:layout_constraintStart_toEndOf="@id/statusIcons" app:layout_constraintEnd_toEndOf="@id/end_guide" app:layout_constraintTop_toTopOf="parent" diff --git a/packages/SystemUI/res/xml/qs_header_new.xml b/packages/SystemUI/res/xml/qs_header_new.xml index f39e6bd65b86..d8a4e7752960 100644 --- a/packages/SystemUI/res/xml/qs_header_new.xml +++ b/packages/SystemUI/res/xml/qs_header_new.xml @@ -40,13 +40,13 @@ android:layout_height="@dimen/large_screen_shade_header_min_height" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/privacy_container" - app:layout_constraintBottom_toTopOf="@id/date" + app:layout_constraintBottom_toBottomOf="@id/carrier_group" app:layout_constraintEnd_toStartOf="@id/carrier_group" app:layout_constraintHorizontal_bias="0" /> <Transform - android:scaleX="2.4" - android:scaleY="2.4" + android:scaleX="2.57" + android:scaleY="2.57" /> </Constraint> @@ -54,11 +54,11 @@ android:id="@+id/date"> <Layout android:layout_width="0dp" - android:layout_height="@dimen/qs_header_non_clickable_element_height" + android:layout_height="@dimen/new_qs_header_non_clickable_element_height" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toStartOf="@id/space" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintTop_toBottomOf="@id/clock" + app:layout_constraintTop_toBottomOf="@id/carrier_group" app:layout_constraintHorizontal_bias="0" app:layout_constraintHorizontal_chainStyle="spread_inside" /> @@ -87,7 +87,7 @@ android:id="@+id/statusIcons"> <Layout android:layout_width="0dp" - android:layout_height="@dimen/qs_header_non_clickable_element_height" + android:layout_height="@dimen/new_qs_header_non_clickable_element_height" app:layout_constrainedWidth="true" app:layout_constraintStart_toEndOf="@id/space" app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon" @@ -101,8 +101,8 @@ android:id="@+id/batteryRemainingIcon"> <Layout android:layout_width="wrap_content" - android:layout_height="@dimen/qs_header_non_clickable_element_height" - app:layout_constraintHeight_min="@dimen/qs_header_non_clickable_element_height" + android:layout_height="@dimen/new_qs_header_non_clickable_element_height" + app:layout_constraintHeight_min="@dimen/new_qs_header_non_clickable_element_height" app:layout_constraintStart_toEndOf="@id/statusIcons" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="@id/date" diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt index f03fee4b0c2d..e3c21cca2263 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt @@ -22,6 +22,7 @@ import android.os.UserHandle import android.provider.Settings import android.util.Log import com.android.systemui.dagger.qualifiers.Main +import com.android.internal.annotations.Keep import com.android.systemui.plugins.ClockController import com.android.systemui.plugins.ClockId import com.android.systemui.plugins.ClockMetadata @@ -201,6 +202,7 @@ open class ClockRegistry( val provider: ClockProvider ) + @Keep private data class ClockSetting( val clockId: ClockId, val _applied_timestamp: Long? diff --git a/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt index 0075ddd73cd3..5277e40492e4 100644 --- a/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt +++ b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt @@ -16,19 +16,29 @@ package com.android.keyguard +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.animation.AnimatorSet +import android.animation.ObjectAnimator import android.content.Context import android.content.res.ColorStateList import android.content.res.TypedArray import android.graphics.Color import android.util.AttributeSet +import android.view.View import com.android.settingslib.Utils +import com.android.systemui.animation.Interpolators /** Displays security messages for the keyguard bouncer. */ -class BouncerKeyguardMessageArea(context: Context?, attrs: AttributeSet?) : +open class BouncerKeyguardMessageArea(context: Context?, attrs: AttributeSet?) : KeyguardMessageArea(context, attrs) { private val DEFAULT_COLOR = -1 private var mDefaultColorState: ColorStateList? = null private var mNextMessageColorState: ColorStateList? = ColorStateList.valueOf(DEFAULT_COLOR) + private val animatorSet = AnimatorSet() + private var textAboutToShow: CharSequence? = null + protected open val SHOW_DURATION_MILLIS = 150L + protected open val HIDE_DURATION_MILLIS = 200L override fun updateTextColor() { var colorState = mDefaultColorState @@ -58,4 +68,46 @@ class BouncerKeyguardMessageArea(context: Context?, attrs: AttributeSet?) : mDefaultColorState = Utils.getColorAttr(context, android.R.attr.textColorPrimary) super.reloadColor() } + + override fun setMessage(msg: CharSequence?) { + if (msg == textAboutToShow || msg == text) { + return + } + textAboutToShow = msg + + if (animatorSet.isRunning) { + animatorSet.cancel() + textAboutToShow = null + } + + val hideAnimator = + ObjectAnimator.ofFloat(this, View.ALPHA, 1f, 0f).apply { + duration = HIDE_DURATION_MILLIS + interpolator = Interpolators.STANDARD_ACCELERATE + } + + hideAnimator.addListener( + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator?) { + super@BouncerKeyguardMessageArea.setMessage(msg) + } + } + ) + val showAnimator = + ObjectAnimator.ofFloat(this, View.ALPHA, 0f, 1f).apply { + duration = SHOW_DURATION_MILLIS + interpolator = Interpolators.STANDARD_DECELERATE + } + + showAnimator.addListener( + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator?) { + textAboutToShow = null + } + } + ) + + animatorSet.playSequentially(hideAnimator, showAnimator) + animatorSet.start() + } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java index f26b9057dc7c..73229c321079 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java @@ -152,6 +152,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> } public void startAppearAnimation() { + mMessageAreaController.setMessage(getInitialMessageResId()); mView.startAppearAnimation(); } @@ -169,6 +170,11 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> return view.indexOfChild(mView); } + /** Determines the message to show in the bouncer when it first appears. */ + protected int getInitialMessageResId() { + return 0; + } + /** Factory for a {@link KeyguardInputViewController}. */ public static class Factory { private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java index c2802f7b6843..2bd3ca59b740 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java @@ -18,7 +18,6 @@ package com.android.keyguard; import android.content.res.ColorStateList; import android.content.res.Configuration; -import android.text.TextUtils; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; @@ -100,15 +99,6 @@ public class KeyguardMessageAreaController<T extends KeyguardMessageArea> mView.setMessage(resId); } - /** - * Set Text if KeyguardMessageArea is empty. - */ - public void setMessageIfEmpty(int resId) { - if (TextUtils.isEmpty(mView.getText())) { - setMessage(resId); - } - } - public void setNextMessageColor(ColorStateList colorState) { mView.setNextMessageColor(colorState); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java index 29e912fdab32..0025986c0e5c 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java @@ -187,7 +187,7 @@ public class KeyguardPasswordViewController @Override void resetState() { mPasswordEntry.setTextOperationUser(UserHandle.of(KeyguardUpdateMonitor.getCurrentUser())); - mMessageAreaController.setMessage(""); + mMessageAreaController.setMessage(getInitialMessageResId()); final boolean wasDisabled = mPasswordEntry.isEnabled(); mView.setPasswordEntryEnabled(true); mView.setPasswordEntryInputEnabled(true); @@ -207,7 +207,6 @@ public class KeyguardPasswordViewController if (reason != KeyguardSecurityView.SCREEN_ON || mShowImeAtScreenOn) { showInput(); } - mMessageAreaController.setMessageIfEmpty(R.string.keyguard_enter_your_password); } private void showInput() { @@ -324,4 +323,9 @@ public class KeyguardPasswordViewController //enabled input method subtype (The current IME should be LatinIME.) || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1; } + + @Override + protected int getInitialMessageResId() { + return R.string.keyguard_enter_your_password; + } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java index 987164557a7a..1f0bd54f8e09 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java @@ -298,12 +298,6 @@ public class KeyguardPatternViewController } @Override - public void onResume(int reason) { - super.onResume(reason); - mMessageAreaController.setMessageIfEmpty(R.string.keyguard_enter_your_pattern); - } - - @Override public boolean needsInput() { return false; } @@ -361,7 +355,7 @@ public class KeyguardPatternViewController } private void displayDefaultSecurityMessage() { - mMessageAreaController.setMessage(""); + mMessageAreaController.setMessage(getInitialMessageResId()); } private void handleAttemptLockout(long elapsedRealtimeDeadline) { @@ -392,4 +386,9 @@ public class KeyguardPatternViewController }.start(); } + + @Override + protected int getInitialMessageResId() { + return R.string.keyguard_enter_your_pattern; + } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java index 59a018ad51df..f7423ed12e68 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java @@ -127,7 +127,6 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB public void onResume(int reason) { super.onResume(reason); mPasswordEntry.requestFocus(); - mMessageAreaController.setMessageIfEmpty(R.string.keyguard_enter_your_pin); } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java index 89fcc47caf57..7876f071fdf5 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java @@ -76,20 +76,13 @@ public class KeyguardPinViewController } @Override - void resetState() { - super.resetState(); - mMessageAreaController.setMessage(""); - } - - @Override - public void startAppearAnimation() { - mMessageAreaController.setMessageIfEmpty(R.string.keyguard_enter_your_pin); - super.startAppearAnimation(); - } - - @Override public boolean startDisappearAnimation(Runnable finishRunnable) { return mView.startDisappearAnimation( mKeyguardUpdateMonitor.needsSlowUnlockTransition(), finishRunnable); } + + @Override + protected int getInitialMessageResId() { + return R.string.keyguard_enter_your_pin; + } } diff --git a/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt index 2c2ab7b39161..6264ce7273f1 100644 --- a/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt +++ b/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt @@ -17,9 +17,9 @@ package com.android.keyguard.logging import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel.DEBUG import com.android.systemui.log.dagger.BiometricMessagesLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel.DEBUG import javax.inject.Inject /** Helper class for logging for [com.android.systemui.biometrics.FaceHelpMessageDeferral] */ diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt index 50012a589b5a..46f3d4e5f6aa 100644 --- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt +++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt @@ -16,15 +16,15 @@ package com.android.keyguard.logging -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel -import com.android.systemui.log.LogLevel.DEBUG -import com.android.systemui.log.LogLevel.ERROR -import com.android.systemui.log.LogLevel.VERBOSE -import com.android.systemui.log.LogLevel.WARNING -import com.android.systemui.log.MessageInitializer -import com.android.systemui.log.MessagePrinter import com.android.systemui.log.dagger.KeyguardLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel +import com.android.systemui.plugins.log.LogLevel.DEBUG +import com.android.systemui.plugins.log.LogLevel.ERROR +import com.android.systemui.plugins.log.LogLevel.VERBOSE +import com.android.systemui.plugins.log.LogLevel.WARNING +import com.android.systemui.plugins.log.MessageInitializer +import com.android.systemui.plugins.log.MessagePrinter import com.google.errorprone.annotations.CompileTimeConstant import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt index 2eee95738b7b..82b32cf616ec 100644 --- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt +++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt @@ -22,13 +22,13 @@ import android.telephony.SubscriptionInfo import com.android.keyguard.ActiveUnlockConfig import com.android.keyguard.KeyguardListenModel import com.android.keyguard.KeyguardUpdateMonitorCallback -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel -import com.android.systemui.log.LogLevel.DEBUG -import com.android.systemui.log.LogLevel.ERROR -import com.android.systemui.log.LogLevel.INFO -import com.android.systemui.log.LogLevel.VERBOSE -import com.android.systemui.log.LogLevel.WARNING +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel +import com.android.systemui.plugins.log.LogLevel.DEBUG +import com.android.systemui.plugins.log.LogLevel.ERROR +import com.android.systemui.plugins.log.LogLevel.INFO +import com.android.systemui.plugins.log.LogLevel.VERBOSE +import com.android.systemui.plugins.log.LogLevel.WARNING import com.android.systemui.log.dagger.KeyguardUpdateMonitorLog import com.google.errorprone.annotations.CompileTimeConstant import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 242a5983a59d..9493975ca00f 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -792,7 +792,11 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, mUdfpsBounds = udfpsProp.getLocation().getRect(); mUdfpsBounds.scale(mScaleFactor); mUdfpsController.updateOverlayParams(udfpsProp.sensorId, - new UdfpsOverlayParams(mUdfpsBounds, mCachedDisplayInfo.getNaturalWidth(), + new UdfpsOverlayParams(mUdfpsBounds, new Rect( + 0, mCachedDisplayInfo.getNaturalHeight() / 2, + mCachedDisplayInfo.getNaturalWidth(), + mCachedDisplayInfo.getNaturalHeight()), + mCachedDisplayInfo.getNaturalWidth(), mCachedDisplayInfo.getNaturalHeight(), mScaleFactor, mCachedDisplayInfo.rotation)); if (!Objects.equals(previousUdfpsBounds, mUdfpsBounds)) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsLogger.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsLogger.kt index 39199d194cc9..0d08b4307f12 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsLogger.kt @@ -16,12 +16,12 @@ package com.android.systemui.biometrics -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel -import com.android.systemui.log.LogLevel.ERROR -import com.android.systemui.log.LogLevel.VERBOSE -import com.android.systemui.log.LogLevel.WARNING import com.android.systemui.log.dagger.UdfpsLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel +import com.android.systemui.plugins.log.LogLevel.ERROR +import com.android.systemui.plugins.log.LogLevel.VERBOSE +import com.android.systemui.plugins.log.LogLevel.WARNING import com.google.errorprone.annotations.CompileTimeConstant import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlay.kt new file mode 100644 index 000000000000..6e78f3d3d6aa --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlay.kt @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2022 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.biometrics + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.PixelFormat +import android.graphics.Rect +import android.hardware.fingerprint.FingerprintManager +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal +import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback +import android.os.Handler +import android.view.MotionEvent +import android.view.View +import android.view.WindowManager +import android.view.WindowManager.LayoutParams.INPUT_FEATURE_SPY +import com.android.keyguard.KeyguardUpdateMonitor +import com.android.systemui.CoreStartable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.util.concurrency.DelayableExecutor +import com.android.systemui.util.concurrency.Execution +import java.util.* +import java.util.concurrent.Executor +import javax.inject.Inject + +private const val TAG = "UdfpsOverlay" + +@SuppressLint("ClickableViewAccessibility") +@SysUISingleton +class UdfpsOverlay +@Inject +constructor( + private val context: Context, + private val execution: Execution, + private val windowManager: WindowManager, + private val fingerprintManager: FingerprintManager?, + private val handler: Handler, + private val biometricExecutor: Executor, + private val alternateTouchProvider: Optional<AlternateUdfpsTouchProvider>, + private val fgExecutor: DelayableExecutor, + private val keyguardUpdateMonitor: KeyguardUpdateMonitor, + private val authController: AuthController, + private val udfpsLogger: UdfpsLogger +) : CoreStartable { + + /** The view, when [isShowing], or null. */ + var overlayView: UdfpsOverlayView? = null + private set + + private var requestId: Long = 0 + private var onFingerDown = false + val size = windowManager.maximumWindowMetrics.bounds + val udfpsProps: MutableList<FingerprintSensorPropertiesInternal> = mutableListOf() + + private var params: UdfpsOverlayParams = UdfpsOverlayParams() + + private val coreLayoutParams = + WindowManager.LayoutParams( + WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG, + 0 /* flags set in computeLayoutParams() */, + PixelFormat.TRANSLUCENT + ) + .apply { + title = TAG + fitInsetsTypes = 0 + gravity = android.view.Gravity.TOP or android.view.Gravity.LEFT + layoutInDisplayCutoutMode = + WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS + flags = Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS + privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY + // Avoid announcing window title. + accessibilityTitle = " " + inputFeatures = INPUT_FEATURE_SPY + } + + fun onTouch(v: View, event: MotionEvent): Boolean { + val view = v as UdfpsOverlayView + + return when (event.action) { + MotionEvent.ACTION_DOWN, + MotionEvent.ACTION_MOVE -> { + onFingerDown = true + if (!view.isDisplayConfigured && alternateTouchProvider.isPresent) { + biometricExecutor.execute { + alternateTouchProvider + .get() + .onPointerDown( + requestId, + event.x.toInt(), + event.y.toInt(), + event.touchMinor, + event.touchMajor + ) + } + fgExecutor.execute { + if (keyguardUpdateMonitor.isFingerprintDetectionRunning) { + keyguardUpdateMonitor.onUdfpsPointerDown(requestId.toInt()) + } + } + + view.configureDisplay { + biometricExecutor.execute { alternateTouchProvider.get().onUiReady() } + } + } + + true + } + MotionEvent.ACTION_UP, + MotionEvent.ACTION_CANCEL -> { + if (onFingerDown && alternateTouchProvider.isPresent) { + biometricExecutor.execute { + alternateTouchProvider.get().onPointerUp(requestId) + } + fgExecutor.execute { + if (keyguardUpdateMonitor.isFingerprintDetectionRunning) { + keyguardUpdateMonitor.onUdfpsPointerUp(requestId.toInt()) + } + } + } + onFingerDown = false + if (view.isDisplayConfigured) { + view.unconfigureDisplay() + } + + true + } + else -> false + } + } + + fun show(requestId: Long): Boolean { + this.requestId = requestId + if (overlayView == null && alternateTouchProvider.isPresent) { + UdfpsOverlayView(context, null).let { + it.overlayParams = params + it.setUdfpsDisplayMode( + UdfpsDisplayMode(context, execution, authController, udfpsLogger) + ) + it.setOnTouchListener { v, event -> onTouch(v, event) } + overlayView = it + } + windowManager.addView(overlayView, coreLayoutParams) + return true + } + + return false + } + + fun hide() { + overlayView?.apply { + windowManager.removeView(this) + setOnTouchListener(null) + } + + overlayView = null + } + + @Override + override fun start() { + fingerprintManager?.addAuthenticatorsRegisteredCallback( + object : IFingerprintAuthenticatorsRegisteredCallback.Stub() { + override fun onAllAuthenticatorsRegistered( + sensors: List<FingerprintSensorPropertiesInternal> + ) { + handler.post { handleAllFingerprintAuthenticatorsRegistered(sensors) } + } + } + ) + } + + private fun handleAllFingerprintAuthenticatorsRegistered( + sensors: List<FingerprintSensorPropertiesInternal> + ) { + for (props in sensors) { + if (props.isAnyUdfpsType) { + udfpsProps.add(props) + } + } + + // Setup param size + if (udfpsProps.isNotEmpty()) { + params = + UdfpsOverlayParams( + sensorBounds = udfpsProps[0].location.rect, + overlayBounds = Rect(0, size.height() / 2, size.width(), size.height()), + naturalDisplayWidth = size.width(), + naturalDisplayHeight = size.height(), + scaleFactor = 1f + ) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayParams.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayParams.kt index d725dfbfe216..c23b0f09f099 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayParams.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayParams.kt @@ -20,6 +20,7 @@ import android.view.Surface.Rotation data class UdfpsOverlayParams( val sensorBounds: Rect = Rect(), + val overlayBounds: Rect = Rect(), val naturalDisplayWidth: Int = 0, val naturalDisplayHeight: Int = 0, val scaleFactor: Float = 1f, @@ -40,4 +41,4 @@ data class UdfpsOverlayParams( } else { naturalDisplayHeight } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayView.kt new file mode 100644 index 000000000000..d37133239531 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayView.kt @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2022 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.biometrics + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.RectF +import android.util.AttributeSet +import android.widget.FrameLayout + +private const val TAG = "UdfpsOverlayView" + +class UdfpsOverlayView(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) { + + private val sensorRect = RectF() + var overlayParams = UdfpsOverlayParams() + private var mUdfpsDisplayMode: UdfpsDisplayMode? = null + + var overlayPaint = Paint() + var sensorPaint = Paint() + val centerPaint = Paint() + + /** True after the call to [configureDisplay] and before the call to [unconfigureDisplay]. */ + var isDisplayConfigured: Boolean = false + private set + + init { + this.setWillNotDraw(false) + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + + overlayPaint.color = Color.argb(120, 255, 0, 0) + overlayPaint.style = Paint.Style.FILL + + sensorPaint.color = Color.argb(150, 134, 204, 255) + sensorPaint.style = Paint.Style.FILL + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + + canvas.drawRect(overlayParams.overlayBounds, overlayPaint) + canvas.drawRect(overlayParams.sensorBounds, sensorPaint) + canvas.drawCircle( + overlayParams.sensorBounds.exactCenterX(), + overlayParams.sensorBounds.exactCenterY(), + overlayParams.sensorBounds.width().toFloat() / 2, + centerPaint + ) + } + + fun setUdfpsDisplayMode(udfpsDisplayMode: UdfpsDisplayMode?) { + mUdfpsDisplayMode = udfpsDisplayMode + } + + fun configureDisplay(onDisplayConfigured: Runnable) { + isDisplayConfigured = true + mUdfpsDisplayMode?.enable(onDisplayConfigured) + } + + fun unconfigureDisplay() { + isDisplayConfigured = false + mUdfpsDisplayMode?.disable(null /* onDisabled */) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt index b1d6e003319a..75640b787a62 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt @@ -16,6 +16,7 @@ package com.android.systemui.biometrics +import android.content.Context import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_OTHER @@ -23,9 +24,9 @@ import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTING import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR import android.hardware.biometrics.BiometricOverlayConstants.REASON_UNKNOWN -import android.hardware.fingerprint.IUdfpsOverlayController import android.hardware.fingerprint.IUdfpsOverlayControllerCallback import android.util.Log +import android.view.LayoutInflater import com.android.systemui.dagger.SysUISingleton import com.android.systemui.statusbar.commandline.Command import com.android.systemui.statusbar.commandline.CommandRegistry @@ -41,14 +42,17 @@ private const val SENSOR_ID = 0 */ @SysUISingleton class UdfpsShell @Inject constructor( - commandRegistry: CommandRegistry + commandRegistry: CommandRegistry, + private val udfpsOverlay: UdfpsOverlay ) : Command { /** * Set in [UdfpsController.java] constructor, used to show and hide the UDFPS overlay. * TODO: inject after b/229290039 is resolved */ - var udfpsOverlayController: IUdfpsOverlayController? = null + var udfpsOverlayController: UdfpsController.UdfpsOverlayController? = null + var context: Context? = null + var inflater: LayoutInflater? = null init { commandRegistry.registerCommand("udfps") { this } @@ -57,6 +61,11 @@ class UdfpsShell @Inject constructor( override fun execute(pw: PrintWriter, args: List<String>) { if (args.size == 1 && args[0] == "hide") { hideOverlay() + } else if (args.size == 2 && args[0] == "udfpsOverlay" && args[1] == "show") { + hideOverlay() + showUdfpsOverlay() + } else if (args.size == 2 && args[0] == "udfpsOverlay" && args[1] == "hide") { + hideUdfpsOverlay() } else if (args.size == 2 && args[0] == "show") { showOverlay(getEnrollmentReason(args[1])) } else { @@ -104,7 +113,17 @@ class UdfpsShell @Inject constructor( ) } + private fun showUdfpsOverlay() { + Log.v(TAG, "showUdfpsOverlay") + udfpsOverlay.show(REQUEST_ID) + } + + private fun hideUdfpsOverlay() { + Log.v(TAG, "hideUdfpsOverlay") + udfpsOverlay.hide() + } + private fun hideOverlay() { udfpsOverlayController?.hideUdfpsOverlay(SENSOR_ID) } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/BluetoothLogger.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/BluetoothLogger.kt index 96af42bfda22..d99625a9fbf2 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/BluetoothLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/BluetoothLogger.kt @@ -17,9 +17,9 @@ package com.android.systemui.bluetooth import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.BluetoothLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import javax.inject.Inject /** Helper class for logging bluetooth events. */ diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt b/packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt index 5b3a982ab5e2..d27708fc04d7 100644 --- a/packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt @@ -20,11 +20,11 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel -import com.android.systemui.log.LogLevel.DEBUG -import com.android.systemui.log.LogLevel.INFO -import com.android.systemui.log.LogMessage +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel +import com.android.systemui.plugins.log.LogLevel.DEBUG +import com.android.systemui.plugins.log.LogLevel.INFO +import com.android.systemui.plugins.log.LogMessage import com.android.systemui.log.dagger.BroadcastDispatcherLog import javax.inject.Inject 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 77b65233c112..d3b5d0edd222 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt @@ -21,6 +21,8 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.os.Bundle +import android.os.RemoteException +import android.service.dreams.IDreamManager import android.view.View import android.view.ViewGroup import android.view.WindowInsets @@ -40,11 +42,13 @@ import javax.inject.Inject */ class ControlsActivity @Inject constructor( private val uiController: ControlsUiController, - private val broadcastDispatcher: BroadcastDispatcher + private val broadcastDispatcher: BroadcastDispatcher, + private val dreamManager: IDreamManager, ) : ComponentActivity() { private lateinit var parent: ViewGroup private lateinit var broadcastReceiver: BroadcastReceiver + private var mExitToDream: Boolean = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -81,17 +85,36 @@ class ControlsActivity @Inject constructor( parent = requireViewById<ViewGroup>(R.id.global_actions_controls) parent.alpha = 0f - uiController.show(parent, { finish() }, this) + uiController.show(parent, { finishOrReturnToDream() }, this) ControlsAnimations.enterAnimation(parent).start() } - override fun onBackPressed() { + override fun onResume() { + super.onResume() + mExitToDream = intent.getBooleanExtra(ControlsUiController.EXIT_TO_DREAM, false) + } + + fun finishOrReturnToDream() { + if (mExitToDream) { + try { + mExitToDream = false + dreamManager.dream() + return + } catch (e: RemoteException) { + // Fall through + } + } finish() } + override fun onBackPressed() { + finishOrReturnToDream() + } + override fun onStop() { super.onStop() + mExitToDream = false uiController.hide() } @@ -106,7 +129,8 @@ class ControlsActivity @Inject constructor( broadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val action = intent.getAction() - if (Intent.ACTION_SCREEN_OFF.equals(action)) { + if (action == Intent.ACTION_SCREEN_OFF || + action == Intent.ACTION_DREAMING_STARTED) { finish() } } @@ -114,6 +138,7 @@ class ControlsActivity @Inject constructor( val filter = IntentFilter() filter.addAction(Intent.ACTION_SCREEN_OFF) + filter.addAction(Intent.ACTION_DREAMING_STARTED) broadcastDispatcher.registerReceiver(broadcastReceiver, filter) } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt index 822f8f2e6191..c1cfbcb0c211 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt @@ -27,6 +27,7 @@ interface ControlsUiController { companion object { public const val TAG = "ControlsUiController" public const val EXTRA_ANIMATE = "extra_animate" + public const val EXIT_TO_DREAM = "extra_exit_to_dream" } fun show(parent: ViewGroup, onDismiss: Runnable, activityContext: Context) diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt index 721c0ba4f865..09743ef7aebf 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt @@ -25,6 +25,7 @@ import com.android.systemui.SliceBroadcastRelayHandler import com.android.systemui.accessibility.SystemActions import com.android.systemui.accessibility.WindowMagnification import com.android.systemui.biometrics.AuthController +import com.android.systemui.biometrics.UdfpsOverlay import com.android.systemui.clipboardoverlay.ClipboardListener import com.android.systemui.dagger.qualifiers.PerUser import com.android.systemui.globalactions.GlobalActionsComponent @@ -218,6 +219,12 @@ abstract class SystemUICoreStartableModule { @ClassKey(KeyguardLiftController::class) abstract fun bindKeyguardLiftController(sysui: KeyguardLiftController): CoreStartable + /** Inject into UdfpsOverlay. */ + @Binds + @IntoMap + @ClassKey(UdfpsOverlay::class) + abstract fun bindUdfpsOverlay(sysui: UdfpsOverlay): CoreStartable + /** Inject into MediaTttSenderCoordinator. */ @Binds @IntoMap diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt index cc5766210406..0e1bfba8aadb 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt @@ -19,10 +19,10 @@ package com.android.systemui.doze import android.view.Display import com.android.systemui.doze.DozeLog.Reason import com.android.systemui.doze.DozeLog.reasonToString -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel.DEBUG -import com.android.systemui.log.LogLevel.ERROR -import com.android.systemui.log.LogLevel.INFO +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel.DEBUG +import com.android.systemui.plugins.log.LogLevel.ERROR +import com.android.systemui.plugins.log.LogLevel.INFO import com.android.systemui.log.dagger.DozeLog import com.android.systemui.statusbar.policy.DevicePostureController import java.text.SimpleDateFormat diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java index 0ccb222c8acc..cedd850ac2ef 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java @@ -210,7 +210,8 @@ public class DreamHomeControlsComplication implements Complication { final Intent intent = new Intent(mContext, ControlsActivity.class) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK) - .putExtra(ControlsUiController.EXTRA_ANIMATE, true); + .putExtra(ControlsUiController.EXTRA_ANIMATE, true) + .putExtra(ControlsUiController.EXIT_TO_DREAM, true); final ActivityLaunchAnimator.Controller controller = v != null ? ActivityLaunchAnimator.Controller.fromView(v, null /* cujType */) diff --git a/packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt b/packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt index 08ef8f3d025f..478f86169718 100644 --- a/packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt @@ -24,7 +24,7 @@ import com.android.systemui.R import com.android.systemui.dump.DumpHandler.Companion.PRIORITY_ARG_CRITICAL import com.android.systemui.dump.DumpHandler.Companion.PRIORITY_ARG_HIGH import com.android.systemui.dump.DumpHandler.Companion.PRIORITY_ARG_NORMAL -import com.android.systemui.log.LogBuffer +import com.android.systemui.plugins.log.LogBuffer import com.android.systemui.shared.system.UncaughtExceptionPreHandlerManager import java.io.PrintWriter import javax.inject.Inject @@ -235,6 +235,7 @@ class DumpHandler @Inject constructor( pw.println("$ <invocation> buffers") pw.println("$ <invocation> bugreport-critical") pw.println("$ <invocation> bugreport-normal") + pw.println("$ <invocation> config") pw.println() pw.println("Targets can be listed:") @@ -313,13 +314,21 @@ class DumpHandler @Inject constructor( const val PRIORITY_ARG_CRITICAL = "CRITICAL" const val PRIORITY_ARG_HIGH = "HIGH" const val PRIORITY_ARG_NORMAL = "NORMAL" + const val PROTO = "--sysui_proto" } } private val PRIORITY_OPTIONS = arrayOf(PRIORITY_ARG_CRITICAL, PRIORITY_ARG_HIGH, PRIORITY_ARG_NORMAL) -private val COMMANDS = arrayOf("bugreport-critical", "bugreport-normal", "buffers", "dumpables") +private val COMMANDS = arrayOf( + "bugreport-critical", + "bugreport-normal", + "buffers", + "dumpables", + "config", + "help" +) private class ParsedArgs( val rawArgs: Array<String>, diff --git a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt index cca04da8f426..dbca65122fcb 100644 --- a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt +++ b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt @@ -18,7 +18,7 @@ package com.android.systemui.dump import android.util.ArrayMap import com.android.systemui.Dumpable -import com.android.systemui.log.LogBuffer +import com.android.systemui.plugins.log.LogBuffer import java.io.PrintWriter import javax.inject.Inject import javax.inject.Singleton diff --git a/packages/SystemUI/src/com/android/systemui/dump/LogBufferEulogizer.kt b/packages/SystemUI/src/com/android/systemui/dump/LogBufferEulogizer.kt index 0eab1afc4119..8299b13d305f 100644 --- a/packages/SystemUI/src/com/android/systemui/dump/LogBufferEulogizer.kt +++ b/packages/SystemUI/src/com/android/systemui/dump/LogBufferEulogizer.kt @@ -19,7 +19,7 @@ package com.android.systemui.dump import android.content.Context import android.util.Log import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.log.LogBuffer +import com.android.systemui.plugins.log.LogBuffer import com.android.systemui.util.io.Files import com.android.systemui.util.time.SystemClock import java.io.IOException diff --git a/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt b/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt index 5651399cb891..f9e341c8629a 100644 --- a/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt @@ -19,6 +19,9 @@ package com.android.systemui.log import android.app.ActivityManager import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dump.DumpManager +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogcatEchoTracker + import javax.inject.Inject @SysUISingleton @@ -26,7 +29,7 @@ class LogBufferFactory @Inject constructor( private val dumpManager: DumpManager, private val logcatEchoTracker: LogcatEchoTracker ) { - /* limit the size of maxPoolSize for low ram (Go) devices */ + /* limitiometricMessageDeferralLogger the size of maxPoolSize for low ram (Go) devices */ private fun adjustMaxSize(requestedMaxSize: Int): Int { return if (ActivityManager.isLowRamDeviceStatic()) { minOf(requestedMaxSize, 20) /* low ram max log size*/ diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/BiometricMessagesLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/BiometricMessagesLog.java index 7f1ad6d20c16..eeadf406060d 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/BiometricMessagesLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/BiometricMessagesLog.java @@ -23,7 +23,7 @@ import java.lang.annotation.RetentionPolicy; import javax.inject.Qualifier; /** - * A {@link com.android.systemui.log.LogBuffer} for BiometricMessages processing such as + * A {@link com.android.systemui.plugins.log.LogBuffer} for BiometricMessages processing such as * {@link com.android.systemui.biometrics.FaceHelpMessageDeferral} */ @Qualifier diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/BroadcastDispatcherLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/BroadcastDispatcherLog.java index 7d1f1c2709fa..5cca1ab2abe7 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/BroadcastDispatcherLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/BroadcastDispatcherLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/CollapsedSbFragmentLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/CollapsedSbFragmentLog.java index 9ca0293fbd86..1d016d837b02 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/CollapsedSbFragmentLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/CollapsedSbFragmentLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/DozeLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/DozeLog.java index 7c5f4025117f..c9f78bcdeef8 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/DozeLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/DozeLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LSShadeTransitionLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LSShadeTransitionLog.java index 08d969b5eb77..76d20bea4bdf 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/LSShadeTransitionLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LSShadeTransitionLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java index 28aa19e18e80..00bf2104b7f2 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java @@ -22,11 +22,11 @@ import android.os.Looper; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.log.LogBuffer; import com.android.systemui.log.LogBufferFactory; -import com.android.systemui.log.LogcatEchoTracker; -import com.android.systemui.log.LogcatEchoTrackerDebug; -import com.android.systemui.log.LogcatEchoTrackerProd; +import com.android.systemui.plugins.log.LogBuffer; +import com.android.systemui.plugins.log.LogcatEchoTracker; +import com.android.systemui.plugins.log.LogcatEchoTrackerDebug; +import com.android.systemui.plugins.log.LogcatEchoTrackerProd; import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.util.Compile; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaBrowserLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaBrowserLog.java index 1d7ba94af4ed..90ced0291805 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaBrowserLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaBrowserLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaCarouselControllerLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaCarouselControllerLog.java index b03655a543f7..e5ac3e2e893b 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaCarouselControllerLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaCarouselControllerLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaMuteAwaitLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaMuteAwaitLog.java index c67d8bebe313..73690ab6c24d 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaMuteAwaitLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaMuteAwaitLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTimeoutListenerLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTimeoutListenerLog.java index 53963fc8d431..99ec05bc8d94 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTimeoutListenerLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTimeoutListenerLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTttReceiverLogBuffer.java b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTttReceiverLogBuffer.java index 5c572e8ef554..1570d434bc62 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTttReceiverLogBuffer.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTttReceiverLogBuffer.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTttSenderLogBuffer.java b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTttSenderLogBuffer.java index edab8c319f87..bf216c6991d2 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTttSenderLogBuffer.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTttSenderLogBuffer.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaViewLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaViewLog.java index 75a34fc22c3c..8c904eab409e 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaViewLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaViewLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NearbyMediaDevicesLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NearbyMediaDevicesLog.java index b1c6dcfcb13b..6d91f0c97c8a 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/NearbyMediaDevicesLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NearbyMediaDevicesLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotifInteractionLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotifInteractionLog.java index 20fc6ff445a6..26af4964f7b8 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/NotifInteractionLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotifInteractionLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationHeadsUpLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationHeadsUpLog.java index fcc184a317b8..61daf9c8d71c 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationHeadsUpLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationHeadsUpLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationInterruptLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationInterruptLog.java index 760fbf3928b6..a59afa0fed1b 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationInterruptLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationInterruptLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLog.java index a0b686487bec..6f8ea7ff2e9b 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationRenderLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationRenderLog.java index 8c8753a07339..835d3490293c 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationRenderLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationRenderLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationSectionLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationSectionLog.java index 7259eebf19b6..6e2bd7b2e1b5 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationSectionLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationSectionLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/PrivacyLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/PrivacyLog.java index e96e532f94bf..77b1bf5fd630 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/PrivacyLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/PrivacyLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/QSFragmentDisableLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/QSFragmentDisableLog.java index 557a254e5c09..9fd166b759d2 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/QSFragmentDisableLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/QSFragmentDisableLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/QSLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/QSLog.java index dd5010cf39a8..dd168bac5654 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/QSLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/QSLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeLog.java index bd0d298ebdee..d24bfcb88188 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarConnectivityLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarConnectivityLog.java index b237f2d74483..67cdb722055b 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarConnectivityLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarConnectivityLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarNetworkControllerLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarNetworkControllerLog.java index f26b3164f488..af0f7c518e64 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarNetworkControllerLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarNetworkControllerLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/SwipeStatusBarAwayLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/SwipeStatusBarAwayLog.java index dd6837563a74..4c276e2bfaab 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/SwipeStatusBarAwayLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/SwipeStatusBarAwayLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/ToastLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/ToastLog.java index 8671dbfdf1fe..ba8b27c23ec1 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/ToastLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/ToastLog.java @@ -18,7 +18,7 @@ package com.android.systemui.log.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselControllerLogger.kt index b1018f9544c0..d40624bfc63a 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselControllerLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselControllerLogger.kt @@ -17,9 +17,9 @@ package com.android.systemui.media import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.MediaCarouselControllerLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import javax.inject.Inject /** A debug logger for [MediaCarouselController]. */ diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt index b52565d57f27..cc06b6c67879 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt @@ -33,7 +33,6 @@ import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dump.DumpManager -import com.android.systemui.people.widget.PeopleSpaceWidgetProvider.EXTRA_USER_HANDLE import com.android.systemui.tuner.TunerService import com.android.systemui.util.Utils import com.android.systemui.util.time.SystemClock diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutLogger.kt b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutLogger.kt index d9c58c0d0d76..8c9e2d88c694 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutLogger.kt @@ -18,11 +18,10 @@ package com.android.systemui.media import android.media.session.PlaybackState import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.MediaTimeoutListenerLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import javax.inject.Inject - private const val TAG = "MediaTimeout" /** diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewLogger.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewLogger.kt index 73868189b362..51c658cb6c54 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaViewLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewLogger.kt @@ -17,9 +17,9 @@ package com.android.systemui.media import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.MediaViewLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import javax.inject.Inject private const val TAG = "MediaView" diff --git a/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowserLogger.kt b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowserLogger.kt index 41f735486c7e..a9c5c61dddbb 100644 --- a/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowserLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowserLogger.kt @@ -18,9 +18,9 @@ package com.android.systemui.media import android.content.ComponentName import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.MediaBrowserLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import javax.inject.Inject /** A logger for events in [ResumeMediaBrowser]. */ diff --git a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java index a8a84331050d..e15e2d3dcccf 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java +++ b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java @@ -17,7 +17,6 @@ package com.android.systemui.media.dagger; import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.log.LogBuffer; import com.android.systemui.log.dagger.MediaTttReceiverLogBuffer; import com.android.systemui.log.dagger.MediaTttSenderLogBuffer; import com.android.systemui.media.MediaDataManager; @@ -33,6 +32,7 @@ import com.android.systemui.media.taptotransfer.MediaTttFlags; import com.android.systemui.media.taptotransfer.common.MediaTttLogger; import com.android.systemui.media.taptotransfer.receiver.MediaTttReceiverLogger; import com.android.systemui.media.taptotransfer.sender.MediaTttSenderLogger; +import com.android.systemui.plugins.log.LogBuffer; import java.util.Optional; diff --git a/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitLogger.kt b/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitLogger.kt index 78f4e012da03..5ace3ea8a05b 100644 --- a/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitLogger.kt @@ -1,9 +1,9 @@ package com.android.systemui.media.muteawait import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.MediaMuteAwaitLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import javax.inject.Inject /** Log messages for [MediaMuteAwaitConnectionManager]. */ diff --git a/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesLogger.kt b/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesLogger.kt index 46b2cc141b3c..78408fce5a36 100644 --- a/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesLogger.kt @@ -1,9 +1,9 @@ package com.android.systemui.media.nearby import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.NearbyMediaDevicesLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import javax.inject.Inject /** Log messages for [NearbyMediaDevicesManager]. */ diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt index b565f3c22f24..38c971ed3f7d 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt @@ -16,8 +16,8 @@ package com.android.systemui.media.taptotransfer.common -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import com.android.systemui.temporarydisplay.TemporaryViewLogger /** diff --git a/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt b/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt index 1ea93474f954..03503fd1ff61 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt @@ -17,10 +17,10 @@ package com.android.systemui.privacy.logging import android.permission.PermissionGroupUsage -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel -import com.android.systemui.log.LogMessage import com.android.systemui.log.dagger.PrivacyLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel +import com.android.systemui.plugins.log.LogMessage import com.android.systemui.privacy.PrivacyDialog import com.android.systemui.privacy.PrivacyItem import java.text.SimpleDateFormat diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt index e5d86cc96f25..025fb228b829 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt @@ -1,8 +1,8 @@ package com.android.systemui.qs -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.QSFragmentDisableLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import com.android.systemui.statusbar.disableflags.DisableFlagsLogger import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java index 4cacbbacec2f..5d03da3cc113 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java @@ -35,6 +35,7 @@ import androidx.annotation.Nullable; import com.android.internal.statusbar.StatusBarIcon; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.qs.QSTileHost; import com.android.systemui.settings.UserTracker; @@ -53,6 +54,7 @@ import javax.inject.Provider; /** * Runs the day-to-day operations of which tiles should be bound and when. */ +@SysUISingleton public class TileServices extends IQSService.Stub { static final int DEFAULT_MAX_BOUND = 3; static final int REDUCED_MAX_BOUND = 1; diff --git a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt index 60380064e098..931dc8df151a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt @@ -17,12 +17,12 @@ package com.android.systemui.qs.logging import android.service.quicksettings.Tile -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel -import com.android.systemui.log.LogLevel.DEBUG -import com.android.systemui.log.LogLevel.VERBOSE -import com.android.systemui.log.LogMessage import com.android.systemui.log.dagger.QSLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel +import com.android.systemui.plugins.log.LogLevel.DEBUG +import com.android.systemui.plugins.log.LogLevel.VERBOSE +import com.android.systemui.plugins.log.LogMessage import com.android.systemui.plugins.qs.QSTile import com.android.systemui.statusbar.StatusBarState import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java index d2d5063c7ae0..b6b657ec82f6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java @@ -26,6 +26,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.logging.MetricsLogger; @@ -43,6 +44,9 @@ import com.android.systemui.statusbar.policy.BaseUserSwitcherAdapter; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.user.data.source.UserRecord; +import java.util.List; +import java.util.stream.Collectors; + import javax.inject.Inject; /** @@ -83,6 +87,13 @@ public class UserDetailView extends PseudoGridView { private final FalsingManager mFalsingManager; private @Nullable UserSwitchDialogController.DialogShower mDialogShower; + @NonNull + @Override + protected List<UserRecord> getUsers() { + return super.getUsers().stream().filter( + userRecord -> !userRecord.isManageUsers).collect(Collectors.toList()); + } + @Inject public Adapter(Context context, UserSwitcherController controller, UiEventLogger uiEventLogger, FalsingManager falsingManager) { diff --git a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt index a494f42985ac..6b540aa9f392 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt @@ -292,6 +292,7 @@ class LargeScreenShadeHeaderController @Inject constructor( clock.addOnLayoutChangeListener { v, _, _, _, _, _, _, _, _ -> val newPivot = if (v.isLayoutRtl) v.width.toFloat() else 0f v.pivotX = newPivot + v.pivotY = v.height.toFloat() / 2 } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/NPVCDownEventState.kt b/packages/SystemUI/src/com/android/systemui/shade/NPVCDownEventState.kt index 07e8b9fe3123..754036d3baa9 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NPVCDownEventState.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/NPVCDownEventState.kt @@ -16,7 +16,7 @@ package com.android.systemui.shade import android.view.MotionEvent import com.android.systemui.dump.DumpsysTableLogger import com.android.systemui.dump.Row -import com.android.systemui.util.collection.RingBuffer +import com.android.systemui.plugins.util.RingBuffer import java.text.SimpleDateFormat import java.util.Locale diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index 29d546fe78c5..8b0b9dee7453 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -2127,7 +2127,8 @@ public final class NotificationPanelViewController { animator.start(); } - private void onFlingEnd(boolean cancelled) { + @VisibleForTesting + void onFlingEnd(boolean cancelled) { mIsFlinging = false; // No overshoot when the animation ends setOverExpansionInternal(0, false /* isFromGesture */); @@ -3868,12 +3869,14 @@ public final class NotificationPanelViewController { } } - private void setIsClosing(boolean isClosing) { + @VisibleForTesting + void setIsClosing(boolean isClosing) { boolean wasClosing = isClosing(); mClosing = isClosing; if (wasClosing != isClosing) { mPanelEventsEmitter.notifyPanelCollapsingChanged(isClosing); } + mAmbientState.setIsClosing(isClosing); } private void updateDozingVisibilities(boolean animate) { @@ -4664,14 +4667,16 @@ public final class NotificationPanelViewController { Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args)); } - private void notifyExpandingStarted() { + @VisibleForTesting + void notifyExpandingStarted() { if (!mExpanding) { mExpanding = true; onExpandingStarted(); } } - private void notifyExpandingFinished() { + @VisibleForTesting + void notifyExpandingFinished() { endClosing(); if (mExpanding) { mExpanding = false; diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt index 7bee0ba17afc..2b788d85a14c 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt @@ -1,10 +1,10 @@ package com.android.systemui.shade import android.view.MotionEvent -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel -import com.android.systemui.log.LogMessage import com.android.systemui.log.dagger.ShadeLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel +import com.android.systemui.plugins.log.LogMessage import com.google.errorprone.annotations.CompileTimeConstant import javax.inject.Inject @@ -12,64 +12,69 @@ private const val TAG = "systemui.shade" /** Lightweight logging utility for the Shade. */ class ShadeLogger @Inject constructor(@ShadeLog private val buffer: LogBuffer) { - fun v(@CompileTimeConstant msg: String) { - buffer.log(TAG, LogLevel.VERBOSE, msg) - } + fun v(@CompileTimeConstant msg: String) { + buffer.log(TAG, LogLevel.VERBOSE, msg) + } - private inline fun log( - logLevel: LogLevel, - initializer: LogMessage.() -> Unit, - noinline printer: LogMessage.() -> String - ) { - buffer.log(TAG, logLevel, initializer, printer) - } + private inline fun log( + logLevel: LogLevel, + initializer: LogMessage.() -> Unit, + noinline printer: LogMessage.() -> String + ) { + buffer.log(TAG, logLevel, initializer, printer) + } - fun onQsInterceptMoveQsTrackingEnabled(h: Float) { - log( - LogLevel.VERBOSE, - { double1 = h.toDouble() }, - { "onQsIntercept: move action, QS tracking enabled. h = $double1" }) - } + fun onQsInterceptMoveQsTrackingEnabled(h: Float) { + log( + LogLevel.VERBOSE, + { double1 = h.toDouble() }, + { "onQsIntercept: move action, QS tracking enabled. h = $double1" } + ) + } - fun logQsTrackingNotStarted( - initialTouchY: Float, - y: Float, - h: Float, - touchSlop: Float, - qsExpanded: Boolean, - collapsedOnDown: Boolean, - keyguardShowing: Boolean, - qsExpansionEnabled: Boolean - ) { - log( - LogLevel.VERBOSE, - { - int1 = initialTouchY.toInt() - int2 = y.toInt() - long1 = h.toLong() - double1 = touchSlop.toDouble() - bool1 = qsExpanded - bool2 = collapsedOnDown - bool3 = keyguardShowing - bool4 = qsExpansionEnabled - }, - { - "QsTrackingNotStarted: initTouchY=$int1,y=$int2,h=$long1,slop=$double1,qsExpanded=" + - "$bool1,collapsedDown=$bool2,keyguardShowing=$bool3,qsExpansion=$bool4" - }) - } + fun logQsTrackingNotStarted( + initialTouchY: Float, + y: Float, + h: Float, + touchSlop: Float, + qsExpanded: Boolean, + collapsedOnDown: Boolean, + keyguardShowing: Boolean, + qsExpansionEnabled: Boolean + ) { + log( + LogLevel.VERBOSE, + { + int1 = initialTouchY.toInt() + int2 = y.toInt() + long1 = h.toLong() + double1 = touchSlop.toDouble() + bool1 = qsExpanded + bool2 = collapsedOnDown + bool3 = keyguardShowing + bool4 = qsExpansionEnabled + }, + { + "QsTrackingNotStarted: initTouchY=$int1,y=$int2,h=$long1,slop=$double1,qsExpanded" + + "=$bool1,collapsedDown=$bool2,keyguardShowing=$bool3,qsExpansion=$bool4" + } + ) + } - fun logMotionEvent(event: MotionEvent, message: String) { - log( - LogLevel.VERBOSE, - { - str1 = message - long1 = event.eventTime - long2 = event.downTime - int1 = event.action - int2 = event.classification - double1 = event.y.toDouble() - }, - { "$str1\neventTime=$long1,downTime=$long2,y=$double1,action=$int1,classification=$int2" }) - } + fun logMotionEvent(event: MotionEvent, message: String) { + log( + LogLevel.VERBOSE, + { + str1 = message + long1 = event.eventTime + long2 = event.downTime + int1 = event.action + int2 = event.classification + double1 = event.y.toDouble() + }, + { + "$str1\neventTime=$long1,downTime=$long2,y=$double1,action=$int1,class=$int2" + } + ) + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt index 7f7ff9cf4881..90c52bd8c9f4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt @@ -17,9 +17,9 @@ package com.android.systemui.statusbar import android.app.PendingIntent -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.NotifInteractionLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import com.android.systemui.statusbar.notification.collection.NotificationEntry import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java index ea7ec4f7fc39..450b757295bc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java @@ -71,9 +71,9 @@ import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.demomode.DemoMode; import com.android.systemui.demomode.DemoModeController; import com.android.systemui.dump.DumpManager; -import com.android.systemui.log.LogBuffer; -import com.android.systemui.log.LogLevel; import com.android.systemui.log.dagger.StatusBarNetworkControllerLog; +import com.android.systemui.plugins.log.LogBuffer; +import com.android.systemui.plugins.log.LogLevel; import com.android.systemui.qs.tiles.dialog.InternetDialogFactory; import com.android.systemui.settings.CurrentUserTracker; import com.android.systemui.statusbar.policy.ConfigurationController; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureLogger.kt index 17feaa842165..9bdff928c44b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureLogger.kt @@ -16,9 +16,9 @@ package com.android.systemui.statusbar.gesture -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.SwipeStatusBarAwayLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import javax.inject.Inject /** Log messages for [SwipeStatusBarAwayGestureHandler]. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt index ad3dfedcdb96..3058fbbc1031 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt @@ -16,9 +16,9 @@ package com.android.systemui.statusbar.notification -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.NotifInteractionLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import com.android.systemui.statusbar.notification.collection.NotificationEntry import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt index 211e37473a70..68d1319699d4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt @@ -16,9 +16,9 @@ package com.android.systemui.statusbar.notification.collection.coalescer -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.NotificationLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import javax.inject.Inject class GroupCoalescerLogger @Inject constructor( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt index e8f352f60da0..2919def16304 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt @@ -1,8 +1,8 @@ package com.android.systemui.statusbar.notification.collection.coordinator -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.NotificationLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import com.android.systemui.statusbar.notification.row.NotificationGuts import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt index 8625cdbc89d5..dfaa291c6bb6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt @@ -1,9 +1,10 @@ package com.android.systemui.statusbar.notification.collection.coordinator import android.util.Log -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel + import com.android.systemui.log.dagger.NotificationHeadsUpLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import javax.inject.Inject private const val TAG = "HeadsUpCoordinator" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt index c4f4ed54e2fa..9558f47af795 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt @@ -16,9 +16,9 @@ package com.android.systemui.statusbar.notification.collection.coordinator -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.NotificationLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import com.android.systemui.statusbar.notification.collection.GroupEntry import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.logKey diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt index c687e1bacbc9..d80445491bda 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt @@ -16,9 +16,9 @@ package com.android.systemui.statusbar.notification.collection.coordinator -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.NotificationLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import javax.inject.Inject private const val TAG = "ShadeEventCoordinator" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt index d8dae5d23f42..8e052c7dcc5d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt @@ -16,11 +16,11 @@ package com.android.systemui.statusbar.notification.collection.listbuilder -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel.DEBUG -import com.android.systemui.log.LogLevel.INFO -import com.android.systemui.log.LogLevel.WARNING import com.android.systemui.log.dagger.NotificationLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel.DEBUG +import com.android.systemui.plugins.log.LogLevel.INFO +import com.android.systemui.plugins.log.LogLevel.WARNING import com.android.systemui.statusbar.notification.NotifPipelineFlags import com.android.systemui.statusbar.notification.collection.GroupEntry import com.android.systemui.statusbar.notification.collection.ListEntry diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt index aa27e1e407f0..911a2d0c2b36 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt @@ -20,13 +20,13 @@ import android.os.RemoteException import android.service.notification.NotificationListenerService import android.service.notification.NotificationListenerService.RankingMap import android.service.notification.StatusBarNotification -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel.DEBUG -import com.android.systemui.log.LogLevel.ERROR -import com.android.systemui.log.LogLevel.INFO -import com.android.systemui.log.LogLevel.WARNING -import com.android.systemui.log.LogLevel.WTF import com.android.systemui.log.dagger.NotificationLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel.DEBUG +import com.android.systemui.plugins.log.LogLevel.ERROR +import com.android.systemui.plugins.log.LogLevel.INFO +import com.android.systemui.plugins.log.LogLevel.WARNING +import com.android.systemui.plugins.log.LogLevel.WTF import com.android.systemui.statusbar.notification.collection.NotifCollection import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason import com.android.systemui.statusbar.notification.collection.NotifCollection.FutureDismissal diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt index 38e3d496a60c..9c71e5c1054c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt @@ -16,9 +16,9 @@ package com.android.systemui.statusbar.notification.collection.render -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.NotificationLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import com.android.systemui.statusbar.notification.NotifPipelineFlags import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection import com.android.systemui.util.Compile diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt index 6d1071c283e3..b4b9438cd6be 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt @@ -16,9 +16,9 @@ package com.android.systemui.statusbar.notification.collection.render -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.NotificationLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import java.lang.RuntimeException import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt index 5dbec8dcba20..d4f11fc141f0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt @@ -1,8 +1,8 @@ package com.android.systemui.statusbar.notification.interruption -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel.INFO import com.android.systemui.log.dagger.NotificationHeadsUpLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel.INFO import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.logKey import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt index 99d320d1c7ca..073b6b041b81 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt @@ -16,11 +16,11 @@ package com.android.systemui.statusbar.notification.interruption -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel.DEBUG -import com.android.systemui.log.LogLevel.INFO -import com.android.systemui.log.LogLevel.WARNING import com.android.systemui.log.dagger.NotificationInterruptLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel.DEBUG +import com.android.systemui.plugins.log.LogLevel.INFO +import com.android.systemui.plugins.log.LogLevel.WARNING import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.logKey import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationRoundnessLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationRoundnessLogger.kt index fe03b2ad6a32..10197a38527e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationRoundnessLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationRoundnessLogger.kt @@ -16,9 +16,9 @@ package com.android.systemui.statusbar.notification.logging -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel.INFO import com.android.systemui.log.dagger.NotificationRenderLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel.INFO import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.ExpandableView import com.android.systemui.statusbar.notification.stack.NotificationSection diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt index ab91926d466a..46fef3f973a7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt @@ -16,9 +16,9 @@ package com.android.systemui.statusbar.notification.row -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel.INFO import com.android.systemui.log.dagger.NotificationLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel.INFO import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.logKey import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt index f9923b2254d7..8a5d29a1ae2d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt @@ -16,9 +16,9 @@ package com.android.systemui.statusbar.notification.row -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel.INFO import com.android.systemui.log.dagger.NotificationLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel.INFO import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.logKey import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java index 2719dd88b7be..b2628e40e77e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java @@ -142,6 +142,11 @@ public class AmbientState implements Dumpable { */ private boolean mIsFlingRequiredAfterLockScreenSwipeUp = false; + /** + * Whether the shade is currently closing. + */ + private boolean mIsClosing; + @VisibleForTesting public boolean isFlingRequiredAfterLockScreenSwipeUp() { return mIsFlingRequiredAfterLockScreenSwipeUp; @@ -717,6 +722,20 @@ public class AmbientState implements Dumpable { && mStatusBarKeyguardViewManager.isBouncerInTransit(); } + /** + * @param isClosing Whether the shade is currently closing. + */ + public void setIsClosing(boolean isClosing) { + mIsClosing = isClosing; + } + + /** + * @return Whether the shade is currently closing. + */ + public boolean isClosing() { + return mIsClosing; + } + @Override public void dump(PrintWriter pw, String[] args) { pw.println("mTopPadding=" + mTopPadding); @@ -761,5 +780,6 @@ public class AmbientState implements Dumpable { + mIsFlingRequiredAfterLockScreenSwipeUp); pw.println("mZDistanceBetweenElements=" + mZDistanceBetweenElements); pw.println("mBaseZHeight=" + mBaseZHeight); + pw.println("mIsClosing=" + mIsClosing); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt index cb7dfe87f7fb..b61c55edadcd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt @@ -17,9 +17,9 @@ package com.android.systemui.statusbar.notification.stack import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.NotificationSectionLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import javax.inject.Inject private const val TAG = "NotifSections" 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 55c577f1ea39..2272411b4314 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 @@ -255,7 +255,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable private boolean mClearAllInProgress; private FooterClearAllListener mFooterClearAllListener; private boolean mFlingAfterUpEvent; - /** * Was the scroller scrolled to the top when the down motion was observed? */ @@ -4020,8 +4019,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable setOwnScrollY(0); } + @VisibleForTesting @ShadeViewRefactor(RefactorComponent.COORDINATOR) - private void setIsExpanded(boolean isExpanded) { + void setIsExpanded(boolean isExpanded) { boolean changed = isExpanded != mIsExpanded; mIsExpanded = isExpanded; mStackScrollAlgorithm.setIsExpanded(isExpanded); @@ -4842,13 +4842,21 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } } + @VisibleForTesting @ShadeViewRefactor(RefactorComponent.COORDINATOR) - private void setOwnScrollY(int ownScrollY) { + void setOwnScrollY(int ownScrollY) { setOwnScrollY(ownScrollY, false /* animateScrollChangeListener */); } @ShadeViewRefactor(RefactorComponent.COORDINATOR) private void setOwnScrollY(int ownScrollY, boolean animateStackYChangeListener) { + // Avoid Flicking during clear all + // when the shade finishes closing, onExpansionStopped will call + // resetScrollPosition to setOwnScrollY to 0 + if (mAmbientState.isClosing()) { + return; + } + if (ownScrollY != mOwnScrollY) { // We still want to call the normal scrolled changed for accessibility reasons onScrollChanged(mScrollX, ownScrollY, mScrollX, mOwnScrollY); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt index 5f79c0e3913a..4c52db7f8732 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt @@ -1,8 +1,8 @@ package com.android.systemui.statusbar.notification.stack -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel.INFO import com.android.systemui.log.dagger.NotificationHeadsUpLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel.INFO import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.logKey import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt index cb4a0884fea4..f5de678a8536 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt @@ -1,8 +1,8 @@ package com.android.systemui.statusbar.notification.stack -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.NotificationHeadsUpLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import com.android.systemui.statusbar.notification.logKey import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt index 02b235493715..4839fe6a7bef 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt @@ -19,9 +19,9 @@ package com.android.systemui.statusbar.phone import android.util.DisplayMetrics import android.view.View import com.android.internal.logging.nano.MetricsProto.MetricsEvent -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.LSShadeTransitionLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.ExpandableView import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt index b9a1413ff791..81edff45c505 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt @@ -17,12 +17,12 @@ package com.android.systemui.statusbar.phone import android.app.PendingIntent -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel.DEBUG -import com.android.systemui.log.LogLevel.ERROR -import com.android.systemui.log.LogLevel.INFO -import com.android.systemui.log.LogLevel.WARNING import com.android.systemui.log.dagger.NotifInteractionLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel.DEBUG +import com.android.systemui.plugins.log.LogLevel.ERROR +import com.android.systemui.plugins.log.LogLevel.INFO +import com.android.systemui.plugins.log.LogLevel.WARNING import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.logKey import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt index 28ed0806a181..d64bc58a0c37 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt @@ -16,9 +16,9 @@ package com.android.systemui.statusbar.phone.fragment -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.CollapsedSbFragmentLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import com.android.systemui.statusbar.disableflags.DisableFlagsLogger import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt index dbb1aa54d8ee..d3cf32fb44ce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt @@ -18,10 +18,10 @@ package com.android.systemui.statusbar.pipeline.shared import android.net.Network import android.net.NetworkCapabilities -import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.StatusBarConnectivityLog +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.toString import javax.inject.Inject import kotlinx.coroutines.flow.Flow diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt index 2f0ebf752a23..28a9b97b8ea6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt @@ -43,11 +43,7 @@ protected constructor( } override fun getCount(): Int { - return if (controller.isKeyguardShowing) { - users.count { !it.isRestricted } - } else { - users.size - } + return users.size } override fun getItem(position: Int): UserRecord { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt index d7c81af53d8b..df1e80b78c9b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt @@ -16,10 +16,10 @@ package com.android.systemui.statusbar.policy -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel.INFO -import com.android.systemui.log.LogLevel.VERBOSE import com.android.systemui.log.dagger.NotificationHeadsUpLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel.INFO +import com.android.systemui.plugins.log.LogLevel.VERBOSE import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.logKey import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt index 606a11a84686..a7185cb18c40 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt @@ -16,8 +16,8 @@ package com.android.systemui.temporarydisplay -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel /** A logger for temporary view changes -- see [TemporaryViewDisplayController]. */ open class TemporaryViewLogger( diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt b/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt index 51541bd3032e..fda511433143 100644 --- a/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt @@ -16,11 +16,11 @@ package com.android.systemui.toast -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel -import com.android.systemui.log.LogLevel.DEBUG -import com.android.systemui.log.LogMessage import com.android.systemui.log.dagger.ToastLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel +import com.android.systemui.plugins.log.LogLevel.DEBUG +import com.android.systemui.plugins.log.LogMessage import javax.inject.Inject private const val TAG = "ToastLog" diff --git a/packages/SystemUI/tests/src/com/android/keyguard/BouncerKeyguardMessageAreaTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/BouncerKeyguardMessageAreaTest.kt new file mode 100644 index 000000000000..9d6aff219148 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/keyguard/BouncerKeyguardMessageAreaTest.kt @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.keyguard + +import android.content.Context +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper.RunWithLooper +import android.util.AttributeSet +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.spy +import org.mockito.Mockito.times +import org.mockito.Mockito.verify + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@RunWithLooper +class BouncerKeyguardMessageAreaTest : SysuiTestCase() { + class FakeBouncerKeyguardMessageArea(context: Context, attrs: AttributeSet?) : + BouncerKeyguardMessageArea(context, attrs) { + override val SHOW_DURATION_MILLIS = 0L + override val HIDE_DURATION_MILLIS = 0L + } + lateinit var underTest: BouncerKeyguardMessageArea + + @Before + fun setup() { + underTest = FakeBouncerKeyguardMessageArea(context, null) + } + + @Test + fun testSetSameMessage() { + val underTestSpy = spy(underTest) + underTestSpy.setMessage("abc") + underTestSpy.setMessage("abc") + verify(underTestSpy, times(1)).text = "abc" + } + + @Test + fun testSetDifferentMessage() { + underTest.setMessage("abc") + underTest.setMessage("def") + assertThat(underTest.text).isEqualTo("def") + } + + @Test + fun testSetNullMessage() { + underTest.setMessage(null) + assertThat(underTest.text).isEqualTo("") + } +} diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java index 69524e5a4537..5d2b0ca4e7ea 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java @@ -17,13 +17,11 @@ package com.android.keyguard; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; -import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; @@ -92,19 +90,4 @@ public class KeyguardMessageAreaControllerTest extends SysuiTestCase { mMessageAreaController.setIsVisible(true); verify(mKeyguardMessageArea).setIsVisible(true); } - - @Test - public void testSetMessageIfEmpty_empty() { - mMessageAreaController.setMessage(""); - mMessageAreaController.setMessageIfEmpty(R.string.keyguard_enter_your_pin); - verify(mKeyguardMessageArea).setMessage(R.string.keyguard_enter_your_pin); - } - - @Test - public void testSetMessageIfEmpty_notEmpty() { - mMessageAreaController.setMessage("abc"); - mMessageAreaController.setMessageIfEmpty(R.string.keyguard_enter_your_pin); - verify(mKeyguardMessageArea, never()).setMessage(getContext() - .getResources().getText(R.string.keyguard_enter_your_pin)); - } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt index b89dbd98968a..b369098cafc0 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt @@ -114,9 +114,8 @@ class KeyguardPasswordViewControllerTest : SysuiTestCase() { } @Test - fun onResume_testSetInitialText() { - keyguardPasswordViewController.onResume(KeyguardSecurityView.SCREEN_ON) - verify(mKeyguardMessageAreaController) - .setMessageIfEmpty(R.string.keyguard_enter_your_password) + fun startAppearAnimation() { + keyguardPasswordViewController.startAppearAnimation() + verify(mKeyguardMessageAreaController).setMessage(R.string.keyguard_enter_your_password) } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt index 3262a77b7711..9eff70487c74 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt @@ -100,16 +100,16 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() { } @Test - fun onPause_clearsTextField() { + fun onPause_resetsText() { mKeyguardPatternViewController.init() mKeyguardPatternViewController.onPause() - verify(mKeyguardMessageAreaController).setMessage("") + verify(mKeyguardMessageAreaController).setMessage(R.string.keyguard_enter_your_pattern) } + @Test - fun onResume_setInitialText() { - mKeyguardPatternViewController.onResume(KeyguardSecurityView.SCREEN_ON) - verify(mKeyguardMessageAreaController) - .setMessageIfEmpty(R.string.keyguard_enter_your_pattern) + fun startAppearAnimation() { + mKeyguardPatternViewController.startAppearAnimation() + verify(mKeyguardMessageAreaController).setMessage(R.string.keyguard_enter_your_pattern) } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java index 97d556b04aa4..ce1101f389c0 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java @@ -113,11 +113,4 @@ public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase { mKeyguardPinViewController.onResume(KeyguardSecurityView.SCREEN_ON); verify(mPasswordEntry).requestFocus(); } - - @Test - public void onResume_setInitialText() { - mKeyguardPinViewController.onResume(KeyguardSecurityView.SCREEN_ON); - verify(mKeyguardMessageAreaController).setMessageIfEmpty(R.string.keyguard_enter_your_pin); - } } - diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt index 9e5bfe53ea05..d9efdeaea04c 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt @@ -98,6 +98,6 @@ class KeyguardPinViewControllerTest : SysuiTestCase() { @Test fun startAppearAnimation() { pinViewController.startAppearAnimation() - verify(keyguardMessageAreaController).setMessageIfEmpty(R.string.keyguard_enter_your_pin) + verify(keyguardMessageAreaController).setMessage(R.string.keyguard_enter_your_pin) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt index baeabc577fb7..cd50144bf2e8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt @@ -163,6 +163,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { val sensorBounds = Rect(0, 0, SENSOR_WIDTH, SENSOR_HEIGHT) overlayParams = UdfpsOverlayParams( sensorBounds, + sensorBounds, DISPLAY_WIDTH, DISPLAY_HEIGHT, scaleFactor = 1f, diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index f210708806ab..eff47bd2ee98 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -414,7 +414,7 @@ public class UdfpsControllerTest extends SysuiTestCase { final float[] scaleFactor = new float[]{1f, displayHeight[1] / (float) displayHeight[0]}; final int[] rotation = new int[]{Surface.ROTATION_0, Surface.ROTATION_90}; final UdfpsOverlayParams oldParams = new UdfpsOverlayParams(sensorBounds[0], - displayWidth[0], displayHeight[0], scaleFactor[0], rotation[0]); + sensorBounds[0], displayWidth[0], displayHeight[0], scaleFactor[0], rotation[0]); for (int i1 = 0; i1 <= 1; ++i1) { for (int i2 = 0; i2 <= 1; ++i2) { @@ -422,8 +422,8 @@ public class UdfpsControllerTest extends SysuiTestCase { for (int i4 = 0; i4 <= 1; ++i4) { for (int i5 = 0; i5 <= 1; ++i5) { final UdfpsOverlayParams newParams = new UdfpsOverlayParams( - sensorBounds[i1], displayWidth[i2], displayHeight[i3], - scaleFactor[i4], rotation[i5]); + sensorBounds[i1], sensorBounds[i1], displayWidth[i2], + displayHeight[i3], scaleFactor[i4], rotation[i5]); if (newParams.equals(oldParams)) { continue; @@ -466,8 +466,8 @@ public class UdfpsControllerTest extends SysuiTestCase { // Initialize the overlay. mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, - new UdfpsOverlayParams(sensorBounds, displayWidth, displayHeight, scaleFactor, - rotation)); + new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight, + scaleFactor, rotation)); // Show the overlay. mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, @@ -477,8 +477,8 @@ public class UdfpsControllerTest extends SysuiTestCase { // Update overlay with the same parameters. mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, - new UdfpsOverlayParams(sensorBounds, displayWidth, displayHeight, scaleFactor, - rotation)); + new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight, + scaleFactor, rotation)); mFgExecutor.runAllReady(); // Ensure the overlay was not recreated. @@ -525,8 +525,8 @@ public class UdfpsControllerTest extends SysuiTestCase { // Test ROTATION_0 mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, - new UdfpsOverlayParams(sensorBounds, displayWidth, displayHeight, scaleFactor, - Surface.ROTATION_0)); + new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight, + scaleFactor, Surface.ROTATION_0)); MotionEvent event = obtainMotionEvent(ACTION_DOWN, displayWidth, displayHeight, touchMinor, touchMajor); mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event); @@ -542,8 +542,8 @@ public class UdfpsControllerTest extends SysuiTestCase { // Test ROTATION_90 reset(mAlternateTouchProvider); mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, - new UdfpsOverlayParams(sensorBounds, displayWidth, displayHeight, scaleFactor, - Surface.ROTATION_90)); + new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight, + scaleFactor, Surface.ROTATION_90)); event = obtainMotionEvent(ACTION_DOWN, displayHeight, 0, touchMinor, touchMajor); mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event); mBiometricsExecutor.runAllReady(); @@ -558,8 +558,8 @@ public class UdfpsControllerTest extends SysuiTestCase { // Test ROTATION_270 reset(mAlternateTouchProvider); mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, - new UdfpsOverlayParams(sensorBounds, displayWidth, displayHeight, scaleFactor, - Surface.ROTATION_270)); + new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight, + scaleFactor, Surface.ROTATION_270)); event = obtainMotionEvent(ACTION_DOWN, 0, displayWidth, touchMinor, touchMajor); mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event); mBiometricsExecutor.runAllReady(); @@ -574,8 +574,8 @@ public class UdfpsControllerTest extends SysuiTestCase { // Test ROTATION_180 reset(mAlternateTouchProvider); mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, - new UdfpsOverlayParams(sensorBounds, displayWidth, displayHeight, scaleFactor, - Surface.ROTATION_180)); + new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight, + scaleFactor, Surface.ROTATION_180)); // ROTATION_180 is not supported. It should be treated like ROTATION_0. event = obtainMotionEvent(ACTION_DOWN, displayWidth, displayHeight, touchMinor, touchMajor); mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event); diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt index b78c06391057..ac936e1a77c5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt @@ -68,7 +68,8 @@ class UdfpsViewTest : SysuiTestCase() { view = LayoutInflater.from(context).inflate(R.layout.udfps_view, null) as UdfpsView view.animationViewController = animationViewController val sensorBounds = SensorLocationInternal("", SENSOR_X, SENSOR_Y, SENSOR_RADIUS).rect - view.overlayParams = UdfpsOverlayParams(sensorBounds, 1920, 1080, 1f, Surface.ROTATION_0) + view.overlayParams = UdfpsOverlayParams(sensorBounds, sensorBounds, 1920, + 1080, 1f, Surface.ROTATION_0) view.setUdfpsDisplayModeProvider(hbmProvider) ViewUtils.attachView(view) } @@ -133,7 +134,8 @@ class UdfpsViewTest : SysuiTestCase() { @Test fun isNotWithinSensorArea() { whenever(animationViewController.touchTranslation).thenReturn(PointF(0f, 0f)) - assertThat(view.isWithinSensorArea(SENSOR_RADIUS * 2.5f, SENSOR_RADIUS.toFloat())).isFalse() + assertThat(view.isWithinSensorArea(SENSOR_RADIUS * 2.5f, SENSOR_RADIUS.toFloat())) + .isFalse() assertThat(view.isWithinSensorArea(SENSOR_RADIUS.toFloat(), SENSOR_RADIUS * 2.5f)).isFalse() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt index fc672016a886..65b44a14d2ad 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt @@ -17,11 +17,13 @@ package com.android.systemui.dump import androidx.test.filters.SmallTest +import com.android.systemui.CoreStartable import com.android.systemui.Dumpable import com.android.systemui.SysuiTestCase -import com.android.systemui.log.LogBuffer +import com.android.systemui.plugins.log.LogBuffer import com.android.systemui.shared.system.UncaughtExceptionPreHandlerManager import com.android.systemui.util.mockito.any +import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.mockito.Mock @@ -30,6 +32,8 @@ import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import java.io.PrintWriter +import java.io.StringWriter +import javax.inject.Provider @SmallTest class DumpHandlerTest : SysuiTestCase() { @@ -66,7 +70,9 @@ class DumpHandlerTest : SysuiTestCase() { mContext, dumpManager, logBufferEulogizer, - mutableMapOf(), + mutableMapOf( + EmptyCoreStartable::class.java to Provider { EmptyCoreStartable() } + ), exceptionHandlerManager ) } @@ -154,4 +160,20 @@ class DumpHandlerTest : SysuiTestCase() { verify(buffer1).dump(pw, 0) verify(buffer2).dump(pw, 0) } -}
\ No newline at end of file + + @Test + fun testConfigDump() { + // GIVEN a StringPrintWriter + val stringWriter = StringWriter() + val spw = PrintWriter(stringWriter) + + // When a config dump is requested + dumpHandler.dump(spw, arrayOf("config")) + + assertThat(stringWriter.toString()).contains(EmptyCoreStartable::class.java.simpleName) + } + + private class EmptyCoreStartable : CoreStartable { + override fun start() {} + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt b/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt index bd029a727ee3..64547f4463d1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt @@ -16,9 +16,9 @@ package com.android.systemui.dump -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel -import com.android.systemui.log.LogcatEchoTracker +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel +import com.android.systemui.plugins.log.LogcatEchoTracker /** * Creates a LogBuffer that will echo everything to logcat, which is useful for debugging tests. diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerTest.kt index 1078cdaa57c4..e009e8651f2a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerTest.kt @@ -19,9 +19,9 @@ package com.android.systemui.media.taptotransfer.common import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager -import com.android.systemui.log.LogBuffer import com.android.systemui.log.LogBufferFactory -import com.android.systemui.log.LogcatEchoTracker +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogcatEchoTracker import com.google.common.truth.Truth.assertThat import java.io.PrintWriter import java.io.StringWriter diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt index aacc695ef301..68c10f20f6f7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt @@ -20,7 +20,7 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager import com.android.systemui.log.LogBufferFactory -import com.android.systemui.log.LogcatEchoTracker +import com.android.systemui.plugins.log.LogcatEchoTracker import com.android.systemui.statusbar.disableflags.DisableFlagsLogger import com.google.common.truth.Truth.assertThat import java.io.PrintWriter diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt index da52a9b1a3c2..bc27bbc13f81 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt @@ -33,6 +33,7 @@ import com.android.systemui.qs.QSUserSwitcherEvent import com.android.systemui.statusbar.policy.UserSwitcherController import com.android.systemui.user.data.source.UserRecord import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -139,6 +140,11 @@ class UserDetailViewAdapterTest : SysuiTestCase() { clickableTest(false, false, mUserDetailItemView, true) } + @Test + fun testManageUsersIsNotAvailable() { + assertNull(adapter.users.find { it.isManageUsers }) + } + private fun createUserRecord(current: Boolean, guest: Boolean) = UserRecord( UserInfo(0 /* id */, "name", 0 /* flags */), diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt index 0151822f871c..14a3bc147808 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt @@ -659,6 +659,51 @@ class LargeScreenShadeHeaderControllerCombinedTest : SysuiTestCase() { verify(privacyIconsController, never()).onParentInvisible() } + @Test + fun clockPivotYInCenter() { + val captor = ArgumentCaptor.forClass(View.OnLayoutChangeListener::class.java) + verify(clock).addOnLayoutChangeListener(capture(captor)) + var height = 100 + val width = 50 + + clock.executeLayoutChange(0, 0, width, height, captor.value) + verify(clock).pivotY = height.toFloat() / 2 + + height = 150 + clock.executeLayoutChange(0, 0, width, height, captor.value) + verify(clock).pivotY = height.toFloat() / 2 + } + + private fun View.executeLayoutChange( + left: Int, + top: Int, + right: Int, + bottom: Int, + listener: View.OnLayoutChangeListener + ) { + val oldLeft = this.left + val oldTop = this.top + val oldRight = this.right + val oldBottom = this.bottom + whenever(this.left).thenReturn(left) + whenever(this.top).thenReturn(top) + whenever(this.right).thenReturn(right) + whenever(this.bottom).thenReturn(bottom) + whenever(this.height).thenReturn(bottom - top) + whenever(this.width).thenReturn(right - left) + listener.onLayoutChange( + this, + oldLeft, + oldTop, + oldRight, + oldBottom, + left, + top, + right, + bottom + ) + } + private fun createWindowInsets( topCutout: Rect? = Rect() ): WindowInsets { diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java index c0dae03023c5..ac02af873920 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java @@ -38,6 +38,7 @@ import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -173,6 +174,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Answer; @@ -1540,6 +1542,33 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { ); } + + /** + * When shade is flinging to close and this fling is not intercepted, + * {@link AmbientState#setIsClosing(boolean)} should be called before + * {@link NotificationStackScrollLayoutController#onExpansionStopped()} + * to ensure scrollY can be correctly set to be 0 + */ + @Test + public void onShadeFlingClosingEnd_mAmbientStateSetClose_thenOnExpansionStopped() { + // Given: Shade is expanded + mNotificationPanelViewController.notifyExpandingFinished(); + mNotificationPanelViewController.setIsClosing(false); + + // When: Shade flings to close not canceled + mNotificationPanelViewController.notifyExpandingStarted(); + mNotificationPanelViewController.setIsClosing(true); + mNotificationPanelViewController.onFlingEnd(false); + + // Then: AmbientState's mIsClosing should be set to false + // before mNotificationStackScrollLayoutController.onExpansionStopped() is called + // to ensure NotificationStackScrollLayout.resetScrollPosition() -> resetScrollPosition + // -> setOwnScrollY(0) can set scrollY to 0 when shade is closed + InOrder inOrder = inOrder(mAmbientState, mNotificationStackScrollLayoutController); + inOrder.verify(mAmbientState).setIsClosing(false); + inOrder.verify(mNotificationStackScrollLayoutController).onExpansionStopped(); + } + private static MotionEvent createMotionEvent(int x, int y, int action) { return MotionEvent.obtain( /* downTime= */ 0, /* eventTime= */ 0, action, x, y, /* metaState= */ 0); diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt index 5b34a95d4fb0..b761647e24e3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt @@ -17,58 +17,58 @@ import org.mockito.MockitoAnnotations @SmallTest class UncaughtExceptionPreHandlerTest : SysuiTestCase() { - private lateinit var preHandlerManager: UncaughtExceptionPreHandlerManager + private lateinit var preHandlerManager: UncaughtExceptionPreHandlerManager - @Mock private lateinit var mockHandler: UncaughtExceptionHandler + @Mock private lateinit var mockHandler: UncaughtExceptionHandler - @Mock private lateinit var mockHandler2: UncaughtExceptionHandler + @Mock private lateinit var mockHandler2: UncaughtExceptionHandler - @Before - fun setUp() { - MockitoAnnotations.initMocks(this) - Thread.setUncaughtExceptionPreHandler(null) - preHandlerManager = UncaughtExceptionPreHandlerManager() - } + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + Thread.setUncaughtExceptionPreHandler(null) + preHandlerManager = UncaughtExceptionPreHandlerManager() + } - @Test - fun registerHandler_registersOnceOnly() { - preHandlerManager.registerHandler(mockHandler) - preHandlerManager.registerHandler(mockHandler) - preHandlerManager.handleUncaughtException(Thread.currentThread(), Exception()) - verify(mockHandler, only()).uncaughtException(any(), any()) - } + @Test + fun registerHandler_registersOnceOnly() { + preHandlerManager.registerHandler(mockHandler) + preHandlerManager.registerHandler(mockHandler) + preHandlerManager.handleUncaughtException(Thread.currentThread(), Exception()) + verify(mockHandler, only()).uncaughtException(any(), any()) + } - @Test - fun registerHandler_setsUncaughtExceptionPreHandler() { - Thread.setUncaughtExceptionPreHandler(null) - preHandlerManager.registerHandler(mockHandler) - assertThat(Thread.getUncaughtExceptionPreHandler()).isNotNull() - } + @Test + fun registerHandler_setsUncaughtExceptionPreHandler() { + Thread.setUncaughtExceptionPreHandler(null) + preHandlerManager.registerHandler(mockHandler) + assertThat(Thread.getUncaughtExceptionPreHandler()).isNotNull() + } - @Test - fun registerHandler_preservesOriginalHandler() { - Thread.setUncaughtExceptionPreHandler(mockHandler) - preHandlerManager.registerHandler(mockHandler2) - preHandlerManager.handleUncaughtException(Thread.currentThread(), Exception()) - verify(mockHandler, only()).uncaughtException(any(), any()) - } + @Test + fun registerHandler_preservesOriginalHandler() { + Thread.setUncaughtExceptionPreHandler(mockHandler) + preHandlerManager.registerHandler(mockHandler2) + preHandlerManager.handleUncaughtException(Thread.currentThread(), Exception()) + verify(mockHandler, only()).uncaughtException(any(), any()) + } - @Test - @Ignore - fun registerHandler_toleratesHandlersThatThrow() { - `when`(mockHandler2.uncaughtException(any(), any())).thenThrow(RuntimeException()) - preHandlerManager.registerHandler(mockHandler2) - preHandlerManager.registerHandler(mockHandler) - preHandlerManager.handleUncaughtException(Thread.currentThread(), Exception()) - verify(mockHandler2, only()).uncaughtException(any(), any()) - verify(mockHandler, only()).uncaughtException(any(), any()) - } + @Test + @Ignore + fun registerHandler_toleratesHandlersThatThrow() { + `when`(mockHandler2.uncaughtException(any(), any())).thenThrow(RuntimeException()) + preHandlerManager.registerHandler(mockHandler2) + preHandlerManager.registerHandler(mockHandler) + preHandlerManager.handleUncaughtException(Thread.currentThread(), Exception()) + verify(mockHandler2, only()).uncaughtException(any(), any()) + verify(mockHandler, only()).uncaughtException(any(), any()) + } - @Test - fun registerHandler_doesNotSetUpTwice() { - UncaughtExceptionPreHandlerManager().registerHandler(mockHandler2) - assertThrows(IllegalStateException::class.java) { - preHandlerManager.registerHandler(mockHandler) + @Test + fun registerHandler_doesNotSetUpTwice() { + UncaughtExceptionPreHandlerManager().registerHandler(mockHandler2) + assertThrows(IllegalStateException::class.java) { + preHandlerManager.registerHandler(mockHandler) + } } - } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt index 8cb530c355bd..5fc0ffe42f55 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt @@ -4,7 +4,7 @@ import android.testing.AndroidTestingRunner import android.util.DisplayMetrics import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.log.LogBuffer +import com.android.systemui.plugins.log.LogBuffer import com.android.systemui.statusbar.notification.row.ExpandableView import com.android.systemui.statusbar.phone.LSShadeTransitionLogger import com.android.systemui.statusbar.phone.LockscreenGestureLogger diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java index f8a0d2fc415c..9c65fac1af45 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java @@ -70,7 +70,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.demomode.DemoModeController; import com.android.systemui.dump.DumpManager; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; import com.android.systemui.telephony.TelephonyListenerManager; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java index ed8a3e16cdd1..4bed4a19b3d9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java @@ -38,7 +38,7 @@ import android.testing.TestableLooper.RunWithLooper; import com.android.settingslib.mobile.TelephonyIcons; import com.android.settingslib.net.DataUsageController; import com.android.systemui.dump.DumpManager; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.util.CarrierConfigTracker; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java index a76676e01c15..d5f5105036d3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java @@ -43,7 +43,7 @@ import com.android.settingslib.mobile.TelephonyIcons; import com.android.settingslib.net.DataUsageController; import com.android.systemui.R; import com.android.systemui.dump.DumpManager; -import com.android.systemui.log.LogBuffer; +import com.android.systemui.plugins.log.LogBuffer; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.util.CarrierConfigTracker; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt index 11798a7a4f96..87f4c323b7cc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt @@ -361,6 +361,22 @@ class AmbientStateTest : SysuiTestCase() { assertThat(sut.isOnKeyguard).isFalse() } // endregion + + // region mIsClosing + @Test + fun isClosing_whenShadeClosing_shouldReturnTrue() { + sut.setIsClosing(true) + + assertThat(sut.isClosing).isTrue() + } + + @Test + fun isClosing_whenShadeFinishClosing_shouldReturnFalse() { + sut.setIsClosing(false) + + assertThat(sut.isClosing).isFalse() + } + // endregion } // region Arrange helper methods. 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 43530365360b..35c8b61b6383 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 @@ -728,6 +728,57 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { verify(mNotificationStackSizeCalculator).computeHeight(any(), anyInt(), anyFloat()); } + @Test + public void testSetOwnScrollY_shadeNotClosing_scrollYChanges() { + // Given: shade is not closing, scrollY is 0 + mAmbientState.setScrollY(0); + assertEquals(0, mAmbientState.getScrollY()); + mAmbientState.setIsClosing(false); + + // When: call NotificationStackScrollLayout.setOwnScrollY to set scrollY to 1 + mStackScroller.setOwnScrollY(1); + + // Then: scrollY should be set to 1 + assertEquals(1, mAmbientState.getScrollY()); + + // Reset scrollY back to 0 to avoid interfering with other tests + mStackScroller.setOwnScrollY(0); + assertEquals(0, mAmbientState.getScrollY()); + } + + @Test + public void testSetOwnScrollY_shadeClosing_scrollYDoesNotChange() { + // Given: shade is closing, scrollY is 0 + mAmbientState.setScrollY(0); + assertEquals(0, mAmbientState.getScrollY()); + mAmbientState.setIsClosing(true); + + // When: call NotificationStackScrollLayout.setOwnScrollY to set scrollY to 1 + mStackScroller.setOwnScrollY(1); + + // Then: scrollY should not change, it should still be 0 + assertEquals(0, mAmbientState.getScrollY()); + + // Reset scrollY and mAmbientState.mIsClosing to avoid interfering with other tests + mAmbientState.setIsClosing(false); + mStackScroller.setOwnScrollY(0); + assertEquals(0, mAmbientState.getScrollY()); + } + + @Test + public void onShadeFlingClosingEnd_scrollYShouldBeSetToZero() { + // Given: mAmbientState.mIsClosing is set to be true + // mIsExpanded is set to be false + mAmbientState.setIsClosing(true); + mStackScroller.setIsExpanded(false); + + // When: onExpansionStopped is called + mStackScroller.onExpansionStopped(); + + // Then: mAmbientState.scrollY should be set to be 0 + assertEquals(mAmbientState.getScrollY(), 0); + } + private void setBarStateForTest(int state) { // Can't inject this through the listener or we end up on the actual implementation // rather than the mock because the spy just coppied the anonymous inner /shruggie. diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt index 65e2964ea332..3a0a94ddd511 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt @@ -20,7 +20,7 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager import com.android.systemui.log.LogBufferFactory -import com.android.systemui.log.LogcatEchoTracker +import com.android.systemui.plugins.log.LogcatEchoTracker import com.android.systemui.statusbar.disableflags.DisableFlagsLogger import com.google.common.truth.Truth.assertThat import java.io.PrintWriter diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java index 3a006adb1933..36e76f47ca4e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java @@ -49,9 +49,9 @@ import com.android.systemui.R; import com.android.systemui.SysuiBaseFragmentTest; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; -import com.android.systemui.log.LogBuffer; -import com.android.systemui.log.LogcatEchoTracker; import com.android.systemui.plugins.DarkIconDispatcher; +import com.android.systemui.plugins.log.LogBuffer; +import com.android.systemui.plugins.log.LogcatEchoTracker; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shade.NotificationPanelViewController; import com.android.systemui.shade.ShadeExpansionStateManager; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt index 0e75c74ef6f5..b32058fca109 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt @@ -22,7 +22,7 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager import com.android.systemui.log.LogBufferFactory -import com.android.systemui.log.LogcatEchoTracker +import com.android.systemui.plugins.log.LogcatEchoTracker import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange import com.google.common.truth.Truth.assertThat diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt index c9f2b4db81ef..13e9f608158e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt @@ -19,9 +19,9 @@ package com.android.systemui.temporarydisplay import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager -import com.android.systemui.log.LogBuffer import com.android.systemui.log.LogBufferFactory -import com.android.systemui.log.LogcatEchoTracker +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogcatEchoTracker import com.google.common.truth.Truth.assertThat import java.io.PrintWriter import java.io.StringWriter diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/collection/RingBufferTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/collection/RingBufferTest.kt deleted file mode 100644 index 5e09b81da4e8..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/util/collection/RingBufferTest.kt +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2022 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.util.collection - -import android.testing.AndroidTestingRunner -import androidx.test.filters.SmallTest -import com.android.systemui.SysuiTestCase -import org.junit.Assert.assertEquals -import org.junit.Assert.assertFalse -import org.junit.Assert.assertSame -import org.junit.Assert.assertThrows -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.MockitoAnnotations - -@SmallTest -@RunWith(AndroidTestingRunner::class) -class RingBufferTest : SysuiTestCase() { - - private val buffer = RingBuffer(5) { TestElement() } - - private val history = mutableListOf<TestElement>() - - @Before - fun setUp() { - MockitoAnnotations.initMocks(this) - } - - @Test - fun testBarelyFillBuffer() { - fillBuffer(5) - - assertEquals(0, buffer[0].id) - assertEquals(1, buffer[1].id) - assertEquals(2, buffer[2].id) - assertEquals(3, buffer[3].id) - assertEquals(4, buffer[4].id) - } - - @Test - fun testPartiallyFillBuffer() { - fillBuffer(3) - - assertEquals(3, buffer.size) - - assertEquals(0, buffer[0].id) - assertEquals(1, buffer[1].id) - assertEquals(2, buffer[2].id) - - assertThrows(IndexOutOfBoundsException::class.java) { buffer[3] } - assertThrows(IndexOutOfBoundsException::class.java) { buffer[4] } - } - - @Test - fun testSpinBuffer() { - fillBuffer(277) - - assertEquals(272, buffer[0].id) - assertEquals(273, buffer[1].id) - assertEquals(274, buffer[2].id) - assertEquals(275, buffer[3].id) - assertEquals(276, buffer[4].id) - assertThrows(IndexOutOfBoundsException::class.java) { buffer[5] } - - assertEquals(5, buffer.size) - } - - @Test - fun testElementsAreRecycled() { - fillBuffer(23) - - assertSame(history[4], buffer[1]) - assertSame(history[9], buffer[1]) - assertSame(history[14], buffer[1]) - assertSame(history[19], buffer[1]) - } - - @Test - fun testIterator() { - fillBuffer(13) - - val iterator = buffer.iterator() - - for (i in 0 until 5) { - assertEquals(history[8 + i], iterator.next()) - } - assertFalse(iterator.hasNext()) - assertThrows(NoSuchElementException::class.java) { iterator.next() } - } - - @Test - fun testForEach() { - fillBuffer(13) - var i = 8 - - buffer.forEach { - assertEquals(history[i], it) - i++ - } - assertEquals(13, i) - } - - private fun fillBuffer(count: Int) { - for (i in 0 until count) { - val elem = buffer.advance() - elem.id = history.size - history.add(elem) - } - } -} - -private class TestElement(var id: Int = 0) { - override fun toString(): String { - return "{TestElement $id}" - } -}
\ No newline at end of file diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index 202f47759272..5d46de335781 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -152,6 +152,8 @@ final class UiModeManagerService extends SystemService { // flag set by resource, whether to start dream immediately upon docking even if unlocked. private boolean mStartDreamImmediatelyOnDock = true; + // flag set by resource, whether to disable dreams when ambient mode suppression is enabled. + private boolean mDreamsDisabledByAmbientModeSuppression = false; // flag set by resource, whether to enable Car dock launch when starting car mode. private boolean mEnableCarDockLaunch = true; // flag set by resource, whether to lock UI mode to the default one or not. @@ -364,6 +366,11 @@ final class UiModeManagerService extends SystemService { mStartDreamImmediatelyOnDock = startDreamImmediatelyOnDock; } + @VisibleForTesting + void setDreamsDisabledByAmbientModeSuppression(boolean disabledByAmbientModeSuppression) { + mDreamsDisabledByAmbientModeSuppression = disabledByAmbientModeSuppression; + } + @Override public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) { mCurrentUser = to.getUserIdentifier(); @@ -424,6 +431,8 @@ final class UiModeManagerService extends SystemService { final Resources res = context.getResources(); mStartDreamImmediatelyOnDock = res.getBoolean( com.android.internal.R.bool.config_startDreamImmediatelyOnDock); + mDreamsDisabledByAmbientModeSuppression = res.getBoolean( + com.android.internal.R.bool.config_dreamsDisabledByAmbientModeSuppressionConfig); mNightMode = res.getInteger( com.android.internal.R.integer.config_defaultNightMode); mDefaultUiModeType = res.getInteger( @@ -1827,10 +1836,14 @@ final class UiModeManagerService extends SystemService { // Send the new configuration. applyConfigurationExternallyLocked(); + final boolean dreamsSuppressed = mDreamsDisabledByAmbientModeSuppression + && mLocalPowerManager.isAmbientDisplaySuppressed(); + // If we did not start a dock app, then start dreaming if appropriate. - if (category != null && !dockAppStarted && (mStartDreamImmediatelyOnDock - || mWindowManager.isKeyguardShowingAndNotOccluded() - || !mPowerManager.isInteractive())) { + if (category != null && !dockAppStarted && !dreamsSuppressed && ( + mStartDreamImmediatelyOnDock + || mWindowManager.isKeyguardShowingAndNotOccluded() + || !mPowerManager.isInteractive())) { mInjector.startDreamWhenDockedIfAppropriate(getContext()); } } diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java index 1e1ebeba5c23..e421c61a2bd6 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java @@ -44,6 +44,7 @@ import android.annotation.Nullable; import android.annotation.UptimeMillisLong; import android.app.Activity; import android.app.ActivityManager; +import android.app.BroadcastOptions; import android.app.IApplicationThread; import android.app.RemoteServiceException.CannotDeliverBroadcastException; import android.app.UidObserver; @@ -534,6 +535,17 @@ class BroadcastQueueModernImpl extends BroadcastQueue { }, mBroadcastConsumerSkipAndCanceled, true); } + final int policy = (r.options != null) + ? r.options.getDeliveryGroupPolicy() : BroadcastOptions.DELIVERY_GROUP_POLICY_ALL; + if (policy == BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT) { + forEachMatchingBroadcast(QUEUE_PREDICATE_ANY, (testRecord, testIndex) -> { + // We only allow caller to remove broadcasts they enqueued + return (r.callingUid == testRecord.callingUid) + && (r.userId == testRecord.userId) + && r.matchesDeliveryGroup(testRecord); + }, mBroadcastConsumerSkipAndCanceled, true); + } + if (r.isReplacePending()) { // Leave the skipped broadcasts intact in queue, so that we can // replace them at their current position during enqueue below diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java index 2d825955ed6c..4f640033d1a4 100644 --- a/services/core/java/com/android/server/am/BroadcastRecord.java +++ b/services/core/java/com/android/server/am/BroadcastRecord.java @@ -796,6 +796,16 @@ final class BroadcastRecord extends Binder { } } + public boolean matchesDeliveryGroup(@NonNull BroadcastRecord other) { + final String key = (options != null) ? options.getDeliveryGroupKey() : null; + final String otherKey = (other.options != null) + ? other.options.getDeliveryGroupKey() : null; + if (key == null && otherKey == null) { + return intent.filterEquals(other.intent); + } + return Objects.equals(key, otherKey); + } + @Override public String toString() { if (mCachedToString == null) { diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 216a48ec699c..3fa41c0f0420 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -16,7 +16,6 @@ package com.android.server.am; -import static android.Manifest.permission.CREATE_USERS; import static android.Manifest.permission.INTERACT_ACROSS_PROFILES; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; @@ -1482,7 +1481,7 @@ class UserController implements Handler.Callback { // defined boolean startUserOnSecondaryDisplay(@UserIdInt int userId, int displayId) { checkCallingHasOneOfThosePermissions("startUserOnSecondaryDisplay", - MANAGE_USERS, CREATE_USERS); + MANAGE_USERS, INTERACT_ACROSS_USERS); // DEFAULT_DISPLAY is used for the current foreground user only Preconditions.checkArgument(displayId != Display.DEFAULT_DISPLAY, diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java b/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java index dec1b559556a..5bc9d2341535 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java +++ b/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java @@ -54,7 +54,7 @@ public class AuthSessionCoordinator implements AuthSessionListener { private AuthResultCoordinator mAuthResultCoordinator; public AuthSessionCoordinator() { - this(SystemClock.currentNetworkTimeClock()); + this(SystemClock.elapsedRealtimeClock()); } @VisibleForTesting diff --git a/services/core/java/com/android/server/biometrics/sensors/MultiBiometricLockoutState.java b/services/core/java/com/android/server/biometrics/sensors/MultiBiometricLockoutState.java index d9bd04d3f1c8..6605d49ece9b 100644 --- a/services/core/java/com/android/server/biometrics/sensors/MultiBiometricLockoutState.java +++ b/services/core/java/com/android/server/biometrics/sensors/MultiBiometricLockoutState.java @@ -22,7 +22,6 @@ import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMET import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_WEAK; import android.hardware.biometrics.BiometricManager; -import android.os.SystemClock; import android.util.Slog; import java.time.Clock; @@ -43,10 +42,6 @@ class MultiBiometricLockoutState { private final Map<Integer, Map<Integer, AuthenticatorState>> mCanUserAuthenticate; private final Clock mClock; - MultiBiometricLockoutState() { - this(SystemClock.currentNetworkTimeClock()); - } - MultiBiometricLockoutState(Clock clock) { mCanUserAuthenticate = new HashMap<>(); mClock = clock; diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java index e653f0466863..6f637b83a694 100644 --- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java @@ -1447,7 +1447,9 @@ public class GnssLocationProvider extends AbstractLocationProvider implements * @return the cell ID or -1 if invalid */ private static long getCidFromCellIdentity(CellIdentity id) { - if (id == null) return -1; + if (id == null) { + return -1; + } long cid = -1; switch(id.getType()) { case CellInfo.TYPE_GSM: cid = ((CellIdentityGsm) id).getCid(); break; @@ -1522,7 +1524,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements for (CellInfo ci : cil) { int status = ci.getCellConnectionStatus(); - if (status == CellInfo.CONNECTION_PRIMARY_SERVING + if (ci.isRegistered() + || status == CellInfo.CONNECTION_PRIMARY_SERVING || status == CellInfo.CONNECTION_SECONDARY_SERVING) { CellIdentity c = ci.getCellIdentity(); int t = getCellType(ci); diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index 5f06ca945eae..77dbde13889b 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -151,10 +151,7 @@ class MediaRouter2ServiceImpl { mContext.registerReceiver(mScreenOnOffReceiver, screenOnOffIntentFilter); } - //////////////////////////////////////////////////////////////// - //// Calls from MediaRouter2 - //// - Should not have @NonNull/@Nullable on any arguments - //////////////////////////////////////////////////////////////// + // Methods that implement MediaRouter2 operations. @NonNull public void enforceMediaContentControlPermission() { @@ -242,7 +239,7 @@ class MediaRouter2ServiceImpl { } } - public void registerRouter2(IMediaRouter2 router, String packageName) { + public void registerRouter2(@NonNull IMediaRouter2 router, @NonNull String packageName) { Objects.requireNonNull(router, "router must not be null"); if (TextUtils.isEmpty(packageName)) { throw new IllegalArgumentException("packageName must not be empty"); @@ -269,7 +266,7 @@ class MediaRouter2ServiceImpl { } } - public void unregisterRouter2(IMediaRouter2 router) { + public void unregisterRouter2(@NonNull IMediaRouter2 router) { Objects.requireNonNull(router, "router must not be null"); final long token = Binder.clearCallingIdentity(); @@ -282,8 +279,8 @@ class MediaRouter2ServiceImpl { } } - public void setDiscoveryRequestWithRouter2(IMediaRouter2 router, - RouteDiscoveryPreference preference) { + public void setDiscoveryRequestWithRouter2(@NonNull IMediaRouter2 router, + @NonNull RouteDiscoveryPreference preference) { Objects.requireNonNull(router, "router must not be null"); Objects.requireNonNull(preference, "preference must not be null"); @@ -302,8 +299,8 @@ class MediaRouter2ServiceImpl { } } - public void setRouteVolumeWithRouter2(IMediaRouter2 router, - MediaRoute2Info route, int volume) { + public void setRouteVolumeWithRouter2(@NonNull IMediaRouter2 router, + @NonNull MediaRoute2Info route, int volume) { Objects.requireNonNull(router, "router must not be null"); Objects.requireNonNull(route, "route must not be null"); @@ -317,9 +314,9 @@ class MediaRouter2ServiceImpl { } } - public void requestCreateSessionWithRouter2(IMediaRouter2 router, int requestId, - long managerRequestId, RoutingSessionInfo oldSession, - MediaRoute2Info route, Bundle sessionHints) { + public void requestCreateSessionWithRouter2(@NonNull IMediaRouter2 router, int requestId, + long managerRequestId, @NonNull RoutingSessionInfo oldSession, + @NonNull MediaRoute2Info route, Bundle sessionHints) { Objects.requireNonNull(router, "router must not be null"); Objects.requireNonNull(oldSession, "oldSession must not be null"); Objects.requireNonNull(route, "route must not be null"); @@ -335,8 +332,8 @@ class MediaRouter2ServiceImpl { } } - public void selectRouteWithRouter2(IMediaRouter2 router, String uniqueSessionId, - MediaRoute2Info route) { + public void selectRouteWithRouter2(@NonNull IMediaRouter2 router, + @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) { Objects.requireNonNull(router, "router must not be null"); Objects.requireNonNull(route, "route must not be null"); if (TextUtils.isEmpty(uniqueSessionId)) { @@ -353,8 +350,8 @@ class MediaRouter2ServiceImpl { } } - public void deselectRouteWithRouter2(IMediaRouter2 router, String uniqueSessionId, - MediaRoute2Info route) { + public void deselectRouteWithRouter2(@NonNull IMediaRouter2 router, + @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) { Objects.requireNonNull(router, "router must not be null"); Objects.requireNonNull(route, "route must not be null"); if (TextUtils.isEmpty(uniqueSessionId)) { @@ -371,8 +368,8 @@ class MediaRouter2ServiceImpl { } } - public void transferToRouteWithRouter2(IMediaRouter2 router, String uniqueSessionId, - MediaRoute2Info route) { + public void transferToRouteWithRouter2(@NonNull IMediaRouter2 router, + @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) { Objects.requireNonNull(router, "router must not be null"); Objects.requireNonNull(route, "route must not be null"); if (TextUtils.isEmpty(uniqueSessionId)) { @@ -389,8 +386,8 @@ class MediaRouter2ServiceImpl { } } - public void setSessionVolumeWithRouter2(IMediaRouter2 router, String uniqueSessionId, - int volume) { + public void setSessionVolumeWithRouter2(@NonNull IMediaRouter2 router, + @NonNull String uniqueSessionId, int volume) { Objects.requireNonNull(router, "router must not be null"); Objects.requireNonNull(uniqueSessionId, "uniqueSessionId must not be null"); @@ -404,7 +401,8 @@ class MediaRouter2ServiceImpl { } } - public void releaseSessionWithRouter2(IMediaRouter2 router, String uniqueSessionId) { + public void releaseSessionWithRouter2(@NonNull IMediaRouter2 router, + @NonNull String uniqueSessionId) { Objects.requireNonNull(router, "router must not be null"); if (TextUtils.isEmpty(uniqueSessionId)) { throw new IllegalArgumentException("uniqueSessionId must not be empty"); @@ -420,13 +418,10 @@ class MediaRouter2ServiceImpl { } } - //////////////////////////////////////////////////////////////// - //// Calls from MediaRouter2Manager - //// - Should not have @NonNull/@Nullable on any arguments - //////////////////////////////////////////////////////////////// + // Methods that implement MediaRouter2Manager operations. @NonNull - public List<RoutingSessionInfo> getRemoteSessions(IMediaRouter2Manager manager) { + public List<RoutingSessionInfo> getRemoteSessions(@NonNull IMediaRouter2Manager manager) { Objects.requireNonNull(manager, "manager must not be null"); final long token = Binder.clearCallingIdentity(); try { @@ -438,7 +433,8 @@ class MediaRouter2ServiceImpl { } } - public void registerManager(IMediaRouter2Manager manager, String packageName) { + public void registerManager(@NonNull IMediaRouter2Manager manager, + @NonNull String packageName) { Objects.requireNonNull(manager, "manager must not be null"); if (TextUtils.isEmpty(packageName)) { throw new IllegalArgumentException("packageName must not be empty"); @@ -458,7 +454,7 @@ class MediaRouter2ServiceImpl { } } - public void unregisterManager(IMediaRouter2Manager manager) { + public void unregisterManager(@NonNull IMediaRouter2Manager manager) { Objects.requireNonNull(manager, "manager must not be null"); final long token = Binder.clearCallingIdentity(); @@ -471,7 +467,7 @@ class MediaRouter2ServiceImpl { } } - public void startScan(IMediaRouter2Manager manager) { + public void startScan(@NonNull IMediaRouter2Manager manager) { Objects.requireNonNull(manager, "manager must not be null"); final long token = Binder.clearCallingIdentity(); try { @@ -483,7 +479,7 @@ class MediaRouter2ServiceImpl { } } - public void stopScan(IMediaRouter2Manager manager) { + public void stopScan(@NonNull IMediaRouter2Manager manager) { Objects.requireNonNull(manager, "manager must not be null"); final long token = Binder.clearCallingIdentity(); try { @@ -495,8 +491,8 @@ class MediaRouter2ServiceImpl { } } - public void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId, - MediaRoute2Info route, int volume) { + public void setRouteVolumeWithManager(@NonNull IMediaRouter2Manager manager, int requestId, + @NonNull MediaRoute2Info route, int volume) { Objects.requireNonNull(manager, "manager must not be null"); Objects.requireNonNull(route, "route must not be null"); @@ -510,10 +506,11 @@ class MediaRouter2ServiceImpl { } } - public void requestCreateSessionWithManager(IMediaRouter2Manager manager, int requestId, - RoutingSessionInfo oldSession, MediaRoute2Info route) { + public void requestCreateSessionWithManager(@NonNull IMediaRouter2Manager manager, + int requestId, @NonNull RoutingSessionInfo oldSession, @NonNull MediaRoute2Info route) { Objects.requireNonNull(manager, "manager must not be null"); Objects.requireNonNull(oldSession, "oldSession must not be null"); + Objects.requireNonNull(route, "route must not be null"); final long token = Binder.clearCallingIdentity(); try { @@ -525,8 +522,8 @@ class MediaRouter2ServiceImpl { } } - public void selectRouteWithManager(IMediaRouter2Manager manager, int requestId, - String uniqueSessionId, MediaRoute2Info route) { + public void selectRouteWithManager(@NonNull IMediaRouter2Manager manager, int requestId, + @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) { Objects.requireNonNull(manager, "manager must not be null"); if (TextUtils.isEmpty(uniqueSessionId)) { throw new IllegalArgumentException("uniqueSessionId must not be empty"); @@ -543,8 +540,8 @@ class MediaRouter2ServiceImpl { } } - public void deselectRouteWithManager(IMediaRouter2Manager manager, int requestId, - String uniqueSessionId, MediaRoute2Info route) { + public void deselectRouteWithManager(@NonNull IMediaRouter2Manager manager, int requestId, + @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) { Objects.requireNonNull(manager, "manager must not be null"); if (TextUtils.isEmpty(uniqueSessionId)) { throw new IllegalArgumentException("uniqueSessionId must not be empty"); @@ -561,8 +558,8 @@ class MediaRouter2ServiceImpl { } } - public void transferToRouteWithManager(IMediaRouter2Manager manager, int requestId, - String uniqueSessionId, MediaRoute2Info route) { + public void transferToRouteWithManager(@NonNull IMediaRouter2Manager manager, int requestId, + @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) { Objects.requireNonNull(manager, "manager must not be null"); if (TextUtils.isEmpty(uniqueSessionId)) { throw new IllegalArgumentException("uniqueSessionId must not be empty"); @@ -579,8 +576,8 @@ class MediaRouter2ServiceImpl { } } - public void setSessionVolumeWithManager(IMediaRouter2Manager manager, int requestId, - String uniqueSessionId, int volume) { + public void setSessionVolumeWithManager(@NonNull IMediaRouter2Manager manager, int requestId, + @NonNull String uniqueSessionId, int volume) { Objects.requireNonNull(manager, "manager must not be null"); if (TextUtils.isEmpty(uniqueSessionId)) { throw new IllegalArgumentException("uniqueSessionId must not be empty"); @@ -596,8 +593,8 @@ class MediaRouter2ServiceImpl { } } - public void releaseSessionWithManager(IMediaRouter2Manager manager, int requestId, - String uniqueSessionId) { + public void releaseSessionWithManager(@NonNull IMediaRouter2Manager manager, int requestId, + @NonNull String uniqueSessionId) { Objects.requireNonNull(manager, "manager must not be null"); if (TextUtils.isEmpty(uniqueSessionId)) { throw new IllegalArgumentException("uniqueSessionId must not be empty"); @@ -681,11 +678,6 @@ class MediaRouter2ServiceImpl { return mUserManagerInternal.getProfileParentId(userId) == mCurrentActiveUserId; } - //////////////////////////////////////////////////////////////// - //// ***Locked methods related to MediaRouter2 - //// - Should have @NonNull/@Nullable on all arguments - //////////////////////////////////////////////////////////////// - @GuardedBy("mLock") private void registerRouter2Locked(@NonNull IMediaRouter2 router, int uid, int pid, @NonNull String packageName, int userId, boolean hasConfigureWifiDisplayPermission, @@ -960,11 +952,6 @@ class MediaRouter2ServiceImpl { DUMMY_REQUEST_ID, routerRecord, uniqueSessionId)); } - //////////////////////////////////////////////////////////// - //// ***Locked methods related to MediaRouter2Manager - //// - Should have @NonNull/@Nullable on all arguments - //////////////////////////////////////////////////////////// - private List<RoutingSessionInfo> getRemoteSessionsLocked( @NonNull IMediaRouter2Manager manager) { final IBinder binder = manager.asBinder(); @@ -1102,8 +1089,8 @@ class MediaRouter2ServiceImpl { } private void requestCreateSessionWithManagerLocked(int requestId, - @NonNull IMediaRouter2Manager manager, - @NonNull RoutingSessionInfo oldSession, @NonNull MediaRoute2Info route) { + @NonNull IMediaRouter2Manager manager, @NonNull RoutingSessionInfo oldSession, + @NonNull MediaRoute2Info route) { ManagerRecord managerRecord = mAllManagerRecords.get(manager.asBinder()); if (managerRecord == null) { return; @@ -1250,8 +1237,7 @@ class MediaRouter2ServiceImpl { } private void releaseSessionWithManagerLocked(int requestId, - @NonNull IMediaRouter2Manager manager, - @NonNull String uniqueSessionId) { + @NonNull IMediaRouter2Manager manager, @NonNull String uniqueSessionId) { final IBinder binder = manager.asBinder(); ManagerRecord managerRecord = mAllManagerRecords.get(binder); @@ -1274,11 +1260,6 @@ class MediaRouter2ServiceImpl { uniqueRequestId, routerRecord, uniqueSessionId)); } - //////////////////////////////////////////////////////////// - //// ***Locked methods used by both router2 and manager - //// - Should have @NonNull/@Nullable on all arguments - //////////////////////////////////////////////////////////// - @GuardedBy("mLock") private UserRecord getOrCreateUserRecordLocked(int userId) { UserRecord userRecord = mUserRecords.get(userId); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 77fea09b5ecc..f459c0e5eeb4 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -61,6 +61,7 @@ import static android.content.pm.PackageManager.FEATURE_LEANBACK; import static android.content.pm.PackageManager.FEATURE_TELECOM; import static android.content.pm.PackageManager.FEATURE_TELEVISION; import static android.content.pm.PackageManager.MATCH_ALL; +import static android.content.pm.PackageManager.MATCH_ANY_USER; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; import static android.content.pm.PackageManager.PERMISSION_GRANTED; @@ -10700,10 +10701,18 @@ public class NotificationManagerService extends SystemService { private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>(); ArrayMap<Pair<ComponentName, Integer>, NotificationListenerFilter> mRequestedNotificationListeners = new ArrayMap<>(); + private final boolean mIsHeadlessSystemUserMode; public NotificationListeners(Context context, Object lock, UserProfiles userProfiles, IPackageManager pm) { + this(context, lock, userProfiles, pm, UserManager.isHeadlessSystemUserMode()); + } + + @VisibleForTesting + public NotificationListeners(Context context, Object lock, UserProfiles userProfiles, + IPackageManager pm, boolean isHeadlessSystemUserMode) { super(context, lock, userProfiles, pm); + this.mIsHeadlessSystemUserMode = isHeadlessSystemUserMode; } @Override @@ -10728,10 +10737,16 @@ public class NotificationManagerService extends SystemService { if (TextUtils.isEmpty(listeners[i])) { continue; } + int packageQueryFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE; + // In the headless system user mode, packages might not be installed for the + // system user. Match packages for any user since apps can be installed only for + // non-system users and would be considering uninstalled for the system user. + if (mIsHeadlessSystemUserMode) { + packageQueryFlags += MATCH_ANY_USER; + } ArraySet<ComponentName> approvedListeners = - this.queryPackageForServices(listeners[i], - MATCH_DIRECT_BOOT_AWARE - | MATCH_DIRECT_BOOT_UNAWARE, USER_SYSTEM); + this.queryPackageForServices(listeners[i], packageQueryFlags, + USER_SYSTEM); for (int k = 0; k < approvedListeners.size(); k++) { ComponentName cn = approvedListeners.valueAt(k); addDefaultComponentOrPackage(cn.flattenToString()); diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java index 3f04264714e4..c4f6836eba7b 100644 --- a/services/core/java/com/android/server/pm/DexOptHelper.java +++ b/services/core/java/com/android/server/pm/DexOptHelper.java @@ -18,6 +18,7 @@ package com.android.server.pm; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; +import static com.android.server.LocalManagerRegistry.ManagerNotFoundException; import static com.android.server.pm.ApexManager.ActiveApexInfo; import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT; @@ -34,6 +35,7 @@ import static com.android.server.pm.PackageManagerServiceUtils.REMOVE_IF_NULL_PK import android.Manifest; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.app.ActivityManager; import android.app.AppGlobals; @@ -56,9 +58,16 @@ import android.util.Slog; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.MetricsLogger; +import com.android.server.LocalManagerRegistry; +import com.android.server.art.ArtManagerLocal; +import com.android.server.art.model.ArtFlags; +import com.android.server.art.model.OptimizeParams; +import com.android.server.art.model.OptimizeResult; +import com.android.server.pm.PackageDexOptimizer.DexOptResult; import com.android.server.pm.dex.DexManager; import com.android.server.pm.dex.DexoptOptions; import com.android.server.pm.pkg.AndroidPackage; +import com.android.server.pm.pkg.PackageState; import com.android.server.pm.pkg.PackageStateInternal; import dalvik.system.DexFile; @@ -72,11 +81,15 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; -final class DexOptHelper { +/** + * Helper class for dex optimization operations in PackageManagerService. + */ +public final class DexOptHelper { private static final long SEVEN_DAYS_IN_MILLISECONDS = 7 * 24 * 60 * 60 * 1000; private final PackageManagerService mPm; @@ -405,11 +418,12 @@ final class DexOptHelper { * {@link PackageDexOptimizer#DEX_OPT_CANCELLED} * {@link PackageDexOptimizer#DEX_OPT_FAILED} */ - @PackageDexOptimizer.DexOptResult + @DexOptResult /* package */ int performDexOptWithStatus(DexoptOptions options) { return performDexOptTraced(options); } + @DexOptResult private int performDexOptTraced(DexoptOptions options) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt"); try { @@ -421,7 +435,13 @@ final class DexOptHelper { // Run dexopt on a given package. Returns true if dexopt did not fail, i.e. // if the package can now be considered up to date for the given filter. + @DexOptResult private int performDexOptInternal(DexoptOptions options) { + Optional<Integer> artSrvRes = performDexOptWithArtService(options); + if (artSrvRes.isPresent()) { + return artSrvRes.get(); + } + AndroidPackage p; PackageSetting pkgSetting; synchronized (mPm.mLock) { @@ -446,8 +466,74 @@ final class DexOptHelper { } } - private int performDexOptInternalWithDependenciesLI(AndroidPackage p, - @NonNull PackageStateInternal pkgSetting, DexoptOptions options) { + /** + * Performs dexopt on the given package using ART Service. + * + * @return a {@link DexOptResult}, or empty if the request isn't supported so that it is + * necessary to fall back to the legacy code paths. + */ + private Optional<Integer> performDexOptWithArtService(DexoptOptions options) { + ArtManagerLocal artManager = getArtManagerLocal(); + if (artManager == null) { + return Optional.empty(); + } + + try (PackageManagerLocal.FilteredSnapshot snapshot = + getPackageManagerLocal().withFilteredSnapshot()) { + PackageState ops = snapshot.getPackageState(options.getPackageName()); + if (ops == null) { + return Optional.of(PackageDexOptimizer.DEX_OPT_FAILED); + } + AndroidPackage oap = ops.getAndroidPackage(); + if (oap == null) { + return Optional.of(PackageDexOptimizer.DEX_OPT_FAILED); + } + if (oap.isApex()) { + return Optional.of(PackageDexOptimizer.DEX_OPT_SKIPPED); + } + + // TODO(b/245301593): Delete the conditional when ART Service supports + // FLAG_SHOULD_INCLUDE_DEPENDENCIES and we can just set it unconditionally. + /*@OptimizeFlags*/ int extraFlags = ops.getUsesLibraries().isEmpty() + ? 0 + : ArtFlags.FLAG_SHOULD_INCLUDE_DEPENDENCIES; + + OptimizeParams params = options.convertToOptimizeParams(extraFlags); + if (params == null) { + return Optional.empty(); + } + + // TODO(b/251903639): Either remove controlDexOptBlocking, or don't ignore it here. + OptimizeResult result; + try { + result = artManager.optimizePackage(snapshot, options.getPackageName(), params); + } catch (UnsupportedOperationException e) { + reportArtManagerFallback(options.getPackageName(), e.toString()); + return Optional.empty(); + } + + // TODO(b/251903639): Move this to ArtManagerLocal.addOptimizePackageDoneCallback when + // it is implemented. + for (OptimizeResult.PackageOptimizeResult pkgRes : result.getPackageOptimizeResults()) { + PackageState ps = snapshot.getPackageState(pkgRes.getPackageName()); + AndroidPackage ap = ps != null ? ps.getAndroidPackage() : null; + if (ap != null) { + CompilerStats.PackageStats stats = mPm.getOrCreateCompilerPackageStats(ap); + for (OptimizeResult.DexContainerFileOptimizeResult dexRes : + pkgRes.getDexContainerFileOptimizeResults()) { + stats.setCompileTime( + dexRes.getDexContainerFile(), dexRes.getDex2oatWallTimeMillis()); + } + } + } + + return Optional.of(convertToDexOptResult(result)); + } + } + + @DexOptResult + private int performDexOptInternalWithDependenciesLI( + AndroidPackage p, @NonNull PackageStateInternal pkgSetting, DexoptOptions options) { // System server gets a special path. if (PLATFORM_PACKAGE_NAME.equals(p.getPackageName())) { return mPm.getDexManager().dexoptSystemServer(options); @@ -514,10 +600,20 @@ final class DexOptHelper { // Whoever is calling forceDexOpt wants a compiled package. // Don't use profiles since that may cause compilation to be skipped. - final int res = performDexOptInternalWithDependenciesLI(pkg, packageState, - new DexoptOptions(packageName, REASON_CMDLINE, - getDefaultCompilerFilter(), null /* splitName */, - DexoptOptions.DEXOPT_FORCE | DexoptOptions.DEXOPT_BOOT_COMPLETE)); + DexoptOptions options = new DexoptOptions(packageName, REASON_CMDLINE, + getDefaultCompilerFilter(), null /* splitName */, + DexoptOptions.DEXOPT_FORCE | DexoptOptions.DEXOPT_BOOT_COMPLETE); + + // performDexOptWithArtService ignores the snapshot and takes its own, so it can race with + // the package checks above, but at worst the effect is only a bit less friendly error + // below. + Optional<Integer> artSrvRes = performDexOptWithArtService(options); + int res; + if (artSrvRes.isPresent()) { + res = artSrvRes.get(); + } else { + res = performDexOptInternalWithDependenciesLI(pkg, packageState, options); + } Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) { @@ -800,4 +896,59 @@ final class DexOptHelper { } return false; } + + private @NonNull PackageManagerLocal getPackageManagerLocal() { + try { + return LocalManagerRegistry.getManagerOrThrow(PackageManagerLocal.class); + } catch (ManagerNotFoundException e) { + throw new RuntimeException(e); + } + } + + /** + * Called whenever we need to fall back from ART Service to the legacy dexopt code. + */ + public static void reportArtManagerFallback(String packageName, String reason) { + // STOPSHIP(b/251903639): Minimize these calls to avoid platform getting shipped with code + // paths that will always bypass ART Service. + Slog.i(TAG, "Falling back to old PackageManager dexopt for " + packageName + ": " + reason); + } + + /** + * Returns {@link ArtManagerLocal} if one is found and should be used for package optimization. + */ + private @Nullable ArtManagerLocal getArtManagerLocal() { + if (!"true".equals(SystemProperties.get("dalvik.vm.useartservice", ""))) { + return null; + } + try { + return LocalManagerRegistry.getManagerOrThrow(ArtManagerLocal.class); + } catch (ManagerNotFoundException e) { + throw new RuntimeException(e); + } + } + + /** + * Converts an ART Service {@link OptimizeResult} to {@link DexOptResult}. + * + * For interfacing {@link ArtManagerLocal} with legacy dex optimization code in PackageManager. + */ + @DexOptResult + private static int convertToDexOptResult(OptimizeResult result) { + /*@OptimizeStatus*/ int status = result.getFinalStatus(); + switch (status) { + case OptimizeResult.OPTIMIZE_SKIPPED: + return PackageDexOptimizer.DEX_OPT_SKIPPED; + case OptimizeResult.OPTIMIZE_FAILED: + return PackageDexOptimizer.DEX_OPT_FAILED; + case OptimizeResult.OPTIMIZE_PERFORMED: + return PackageDexOptimizer.DEX_OPT_PERFORMED; + case OptimizeResult.OPTIMIZE_CANCELLED: + return PackageDexOptimizer.DEX_OPT_CANCELLED; + default: + throw new IllegalArgumentException("OptimizeResult for " + + result.getPackageOptimizeResults().get(0).getPackageName() + + " has unsupported status " + status); + } + } } diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index d25bca76245b..2a2410fd1767 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -652,12 +652,6 @@ public class PackageDexOptimizer { @DexOptResult private int dexOptSecondaryDexPathLI(ApplicationInfo info, String path, PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options) { - if (options.isDexoptOnlySharedDex() && !dexUseInfo.isUsedByOtherApps()) { - // We are asked to optimize only the dex files used by other apps and this is not - // on of them: skip it. - return DEX_OPT_SKIPPED; - } - String compilerFilter = getRealCompilerFilter(info, options.getCompilerFilter(), dexUseInfo.isUsedByOtherApps()); // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct flags. diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 60f247843bb7..657707400da6 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -2633,6 +2633,9 @@ public class UserManagerService extends IUserManager.Stub { /** @return a specific user restriction that's in effect currently. */ @Override public boolean hasUserRestriction(String restrictionKey, @UserIdInt int userId) { + if (!userExists(userId)) { + return false; + } checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "hasUserRestriction"); return mLocalService.hasUserRestriction(restrictionKey, userId); } diff --git a/services/core/java/com/android/server/pm/dex/DexoptOptions.java b/services/core/java/com/android/server/pm/dex/DexoptOptions.java index ea233161b4af..f5557c417f1b 100644 --- a/services/core/java/com/android/server/pm/dex/DexoptOptions.java +++ b/services/core/java/com/android/server/pm/dex/DexoptOptions.java @@ -18,6 +18,16 @@ package com.android.server.pm.dex; import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason; +import android.annotation.Nullable; + +import com.android.server.art.ReasonMapping; +import com.android.server.art.model.ArtFlags; +import com.android.server.art.model.OptimizeParams; +import com.android.server.pm.DexOptHelper; +import com.android.server.pm.PackageManagerService; + +import dalvik.system.DexFile; + /** * Options used for dexopt invocations. */ @@ -40,10 +50,6 @@ public final class DexoptOptions { // will only consider the primary apk. public static final int DEXOPT_ONLY_SECONDARY_DEX = 1 << 3; - // When set, dexopt will optimize only dex files that are used by other apps. - // Currently, this flag is ignored for primary apks. - public static final int DEXOPT_ONLY_SHARED_DEX = 1 << 4; - // When set, dexopt will attempt to scale down the optimizations previously applied in order // save disk space. public static final int DEXOPT_DOWNGRADE = 1 << 5; @@ -105,7 +111,6 @@ public final class DexoptOptions { DEXOPT_FORCE | DEXOPT_BOOT_COMPLETE | DEXOPT_ONLY_SECONDARY_DEX | - DEXOPT_ONLY_SHARED_DEX | DEXOPT_DOWNGRADE | DEXOPT_AS_SHARED_LIBRARY | DEXOPT_IDLE_BACKGROUND_JOB | @@ -146,10 +151,6 @@ public final class DexoptOptions { return (mFlags & DEXOPT_ONLY_SECONDARY_DEX) != 0; } - public boolean isDexoptOnlySharedDex() { - return (mFlags & DEXOPT_ONLY_SHARED_DEX) != 0; - } - public boolean isDowngrade() { return (mFlags & DEXOPT_DOWNGRADE) != 0; } @@ -198,4 +199,133 @@ public final class DexoptOptions { mSplitName, mFlags); } + + /** + * Returns an {@link OptimizeParams} instance corresponding to this object, for use with + * {@link com.android.server.art.ArtManagerLocal}. + * + * @param extraFlags extra {@link ArtFlags#OptimizeFlags} to set in the returned + * {@code OptimizeParams} beyond those converted from this object + * @return null if the settings cannot be accurately represented, and hence the old + * PackageManager/installd code paths need to be used. + */ + public @Nullable OptimizeParams convertToOptimizeParams(/*@OptimizeFlags*/ int extraFlags) { + if (mSplitName != null) { + DexOptHelper.reportArtManagerFallback( + mPackageName, "Request to optimize only split " + mSplitName); + return null; + } + + /*@OptimizeFlags*/ int flags = extraFlags; + if ((mFlags & DEXOPT_CHECK_FOR_PROFILES_UPDATES) == 0 + && DexFile.isProfileGuidedCompilerFilter(mCompilerFilter)) { + // ART Service doesn't support bypassing this, so not setting this flag is not + // supported. + DexOptHelper.reportArtManagerFallback(mPackageName, + "DEXOPT_CHECK_FOR_PROFILES_UPDATES not set with profile compiler filter"); + return null; + } + if ((mFlags & DEXOPT_FORCE) != 0) { + flags |= ArtFlags.FLAG_FORCE; + } + if ((mFlags & DEXOPT_ONLY_SECONDARY_DEX) != 0) { + flags |= ArtFlags.FLAG_FOR_SECONDARY_DEX; + } else { + flags |= ArtFlags.FLAG_FOR_PRIMARY_DEX; + } + if ((mFlags & DEXOPT_DOWNGRADE) != 0) { + flags |= ArtFlags.FLAG_SHOULD_DOWNGRADE; + } + if ((mFlags & DEXOPT_INSTALL_WITH_DEX_METADATA_FILE) == 0) { + // ART Service cannot be instructed to ignore a DM file if present, so not setting this + // flag is not supported. + DexOptHelper.reportArtManagerFallback( + mPackageName, "DEXOPT_INSTALL_WITH_DEX_METADATA_FILE not set"); + return null; + } + + /*@PriorityClassApi*/ int priority; + // Replicates logic in RunDex2Oat::PrepareCompilerRuntimeAndPerfConfigFlags in installd. + if ((mFlags & DEXOPT_BOOT_COMPLETE) != 0) { + if ((mFlags & DEXOPT_FOR_RESTORE) != 0) { + priority = ArtFlags.PRIORITY_INTERACTIVE_FAST; + } else { + // TODO(b/251903639): Repurpose DEXOPT_IDLE_BACKGROUND_JOB to choose new + // dalvik.vm.background-dex2oat-* properties. + priority = ArtFlags.PRIORITY_INTERACTIVE; + } + } else { + priority = ArtFlags.PRIORITY_BOOT; + } + + // The following flags in mFlags are ignored: + // + // - DEXOPT_AS_SHARED_LIBRARY: It's implicit with ART Service since it always looks at + // <uses-library> rather than actual dependencies. + // + // We don't require it to be set either. It's safe when switching between old and new + // code paths since the only effect is that some packages may be unnecessarily compiled + // without user profiles. + // + // - DEXOPT_IDLE_BACKGROUND_JOB: Its only effect is to allow the debug variant dex2oatd to + // be used, but ART Service never uses that (cf. Artd::GetDex2Oat in artd.cc). + + String reason; + switch (mCompilationReason) { + case PackageManagerService.REASON_FIRST_BOOT: + reason = ReasonMapping.REASON_FIRST_BOOT; + break; + case PackageManagerService.REASON_BOOT_AFTER_OTA: + reason = ReasonMapping.REASON_BOOT_AFTER_OTA; + break; + case PackageManagerService.REASON_POST_BOOT: + // This reason will go away with the legacy dexopt code. + DexOptHelper.reportArtManagerFallback( + mPackageName, "Unsupported compilation reason REASON_POST_BOOT"); + return null; + case PackageManagerService.REASON_INSTALL: + reason = ReasonMapping.REASON_INSTALL; + break; + case PackageManagerService.REASON_INSTALL_FAST: + reason = ReasonMapping.REASON_INSTALL_FAST; + break; + case PackageManagerService.REASON_INSTALL_BULK: + reason = ReasonMapping.REASON_INSTALL_BULK; + break; + case PackageManagerService.REASON_INSTALL_BULK_SECONDARY: + reason = ReasonMapping.REASON_INSTALL_BULK_SECONDARY; + break; + case PackageManagerService.REASON_INSTALL_BULK_DOWNGRADED: + reason = ReasonMapping.REASON_INSTALL_BULK_DOWNGRADED; + break; + case PackageManagerService.REASON_INSTALL_BULK_SECONDARY_DOWNGRADED: + reason = ReasonMapping.REASON_INSTALL_BULK_SECONDARY_DOWNGRADED; + break; + case PackageManagerService.REASON_BACKGROUND_DEXOPT: + reason = ReasonMapping.REASON_BG_DEXOPT; + break; + case PackageManagerService.REASON_INACTIVE_PACKAGE_DOWNGRADE: + reason = ReasonMapping.REASON_INACTIVE; + break; + case PackageManagerService.REASON_CMDLINE: + reason = ReasonMapping.REASON_CMDLINE; + break; + case PackageManagerService.REASON_SHARED: + case PackageManagerService.REASON_AB_OTA: + // REASON_SHARED shouldn't go into this code path - it's only used at lower levels + // in PackageDexOptimizer. + // TODO(b/251921228): OTA isn't supported, so REASON_AB_OTA shouldn't come this way + // either. + throw new UnsupportedOperationException( + "ART Service unsupported compilation reason " + mCompilationReason); + default: + throw new IllegalArgumentException( + "Invalid compilation reason " + mCompilationReason); + } + + return new OptimizeParams.Builder(reason, flags) + .setCompilerFilter(mCompilerFilter) + .setPriorityClass(priority) + .build(); + } } diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 5abc875a697f..4784723b7735 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -6768,6 +6768,11 @@ public final class PowerManagerService extends SystemService public void nap(long eventTime, boolean allowWake) { napInternal(eventTime, Process.SYSTEM_UID, allowWake); } + + @Override + public boolean isAmbientDisplaySuppressed() { + return mAmbientDisplaySuppressionController.isSuppressed(); + } } /** diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index 214a2c197a5c..3c457e1cc277 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -2578,6 +2578,9 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { // activity lifecycle transaction to make sure the override pending app // transition will be applied immediately. targetActivity.applyOptionsAnimation(); + if (activityOptions != null && activityOptions.getLaunchCookie() != null) { + targetActivity.mLaunchCookie = activityOptions.getLaunchCookie(); + } } finally { mActivityMetricsLogger.notifyActivityLaunched(launchingState, START_TASK_TO_FRONT, false /* newActivityCreated */, diff --git a/services/core/jni/gnss/AGnssRil.cpp b/services/core/jni/gnss/AGnssRil.cpp index 424ffd463713..34e4976dcca0 100644 --- a/services/core/jni/gnss/AGnssRil.cpp +++ b/services/core/jni/gnss/AGnssRil.cpp @@ -55,13 +55,13 @@ jboolean AGnssRil::setRefLocation(jint type, jint mcc, jint mnc, jint lac, jlong case IAGnssRil::AGnssRefLocationType::UMTS_CELLID: case IAGnssRil::AGnssRefLocationType::LTE_CELLID: case IAGnssRil::AGnssRefLocationType::NR_CELLID: - location.cellID.mcc = mcc; - location.cellID.mnc = mnc; - location.cellID.lac = lac; - location.cellID.cid = cid; - location.cellID.tac = tac; - location.cellID.pcid = pcid; - location.cellID.arfcn = arfcn; + location.cellID.mcc = static_cast<int>(mcc); + location.cellID.mnc = static_cast<int>(mnc); + location.cellID.lac = static_cast<int>(lac); + location.cellID.cid = static_cast<long>(cid); + location.cellID.tac = static_cast<int>(tac); + location.cellID.pcid = static_cast<int>(pcid); + location.cellID.arfcn = static_cast<int>(arfcn); break; default: ALOGE("Unknown cellid (%s:%d).", __FUNCTION__, __LINE__); @@ -106,20 +106,24 @@ jboolean AGnssRil_V1_0::setSetId(jint type, const jstring& setid_string) { return checkHidlReturn(result, "IAGnssRil_V1_0 setSetId() failed."); } -jboolean AGnssRil_V1_0::setRefLocation(jint type, jint mcc, jint mnc, jint lac, jlong cid, jint, - jint, jint) { +jboolean AGnssRil_V1_0::setRefLocation(jint type, jint mcc, jint mnc, jint lac, jlong cid, jint tac, + jint pcid, jint) { IAGnssRil_V1_0::AGnssRefLocation location; - switch (static_cast<IAGnssRil_V1_0::AGnssRefLocationType>(type)) { + location.type = static_cast<IAGnssRil_V1_0::AGnssRefLocationType>(type); + + switch (location.type) { case IAGnssRil_V1_0::AGnssRefLocationType::GSM_CELLID: case IAGnssRil_V1_0::AGnssRefLocationType::UMTS_CELLID: - location.type = static_cast<IAGnssRil_V1_0::AGnssRefLocationType>(type); - location.cellID.mcc = mcc; - location.cellID.mnc = mnc; - location.cellID.lac = lac; - location.cellID.cid = cid; + case IAGnssRil_V1_0::AGnssRefLocationType::LTE_CELLID: + location.cellID.mcc = static_cast<uint16_t>(mcc); + location.cellID.mnc = static_cast<uint16_t>(mnc); + location.cellID.lac = static_cast<uint16_t>(lac); + location.cellID.cid = static_cast<uint32_t>(cid); + location.cellID.tac = static_cast<uint16_t>(tac); + location.cellID.pcid = static_cast<uint16_t>(pcid); break; default: - ALOGE("Neither a GSM nor a UMTS cellid (%s:%d).", __FUNCTION__, __LINE__); + ALOGE("Unknown cellid (%s:%d).", __FUNCTION__, __LINE__); return JNI_FALSE; break; } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java index 90b1f4ecdcb3..abc32c9339ae 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java @@ -39,6 +39,8 @@ import android.app.AppOpsManager; import android.app.BroadcastOptions; import android.content.Intent; import android.content.IntentFilter; +import android.media.AudioManager; +import android.os.Bundle; import android.os.HandlerThread; import android.os.UserHandle; import android.provider.Settings; @@ -386,4 +388,86 @@ public class BroadcastQueueModernImplTest { assertEquals(Intent.ACTION_SCREEN_OFF, queue.getActive().intent.getAction()); assertTrue(queue.isEmpty()); } + + /** + * Verify that sending a broadcast with DELIVERY_GROUP_POLICY_MOST_RECENT works as expected. + */ + @Test + public void testDeliveryGroupPolicy_mostRecent() { + final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK); + final BroadcastOptions optionsTimeTick = BroadcastOptions.makeBasic(); + optionsTimeTick.setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT); + + final Intent musicVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION); + musicVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, + AudioManager.STREAM_MUSIC); + final BroadcastOptions optionsMusicVolumeChanged = BroadcastOptions.makeBasic(); + optionsMusicVolumeChanged.setDeliveryGroupPolicy( + BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT); + optionsMusicVolumeChanged.setDeliveryGroupKey("audio", + String.valueOf(AudioManager.STREAM_MUSIC)); + + final Intent alarmVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION); + alarmVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, + AudioManager.STREAM_ALARM); + final BroadcastOptions optionsAlarmVolumeChanged = BroadcastOptions.makeBasic(); + optionsAlarmVolumeChanged.setDeliveryGroupPolicy( + BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT); + optionsAlarmVolumeChanged.setDeliveryGroupKey("audio", + String.valueOf(AudioManager.STREAM_ALARM)); + + // Halt all processing so that we get a consistent view + mHandlerThread.getLooper().getQueue().postSyncBarrier(); + + mImpl.enqueueBroadcastLocked(makeBroadcastRecord(timeTick, optionsTimeTick)); + mImpl.enqueueBroadcastLocked(makeBroadcastRecord(musicVolumeChanged, + optionsMusicVolumeChanged)); + mImpl.enqueueBroadcastLocked(makeBroadcastRecord(alarmVolumeChanged, + optionsAlarmVolumeChanged)); + mImpl.enqueueBroadcastLocked(makeBroadcastRecord(musicVolumeChanged, + optionsMusicVolumeChanged)); + + final BroadcastProcessQueue queue = mImpl.getProcessQueue(PACKAGE_GREEN, + getUidForPackage(PACKAGE_GREEN)); + // Verify that the older musicVolumeChanged has been removed. + verifyPendingRecords(queue, + List.of(timeTick, alarmVolumeChanged, musicVolumeChanged)); + + mImpl.enqueueBroadcastLocked(makeBroadcastRecord(timeTick, optionsTimeTick)); + mImpl.enqueueBroadcastLocked(makeBroadcastRecord(alarmVolumeChanged, + optionsAlarmVolumeChanged)); + mImpl.enqueueBroadcastLocked(makeBroadcastRecord(musicVolumeChanged, + optionsMusicVolumeChanged)); + mImpl.enqueueBroadcastLocked(makeBroadcastRecord(alarmVolumeChanged, + optionsAlarmVolumeChanged)); + // Verify that the older alarmVolumeChanged has been removed. + verifyPendingRecords(queue, + List.of(timeTick, musicVolumeChanged, alarmVolumeChanged)); + + mImpl.enqueueBroadcastLocked(makeBroadcastRecord(timeTick, optionsTimeTick)); + mImpl.enqueueBroadcastLocked(makeBroadcastRecord(musicVolumeChanged, + optionsMusicVolumeChanged)); + mImpl.enqueueBroadcastLocked(makeBroadcastRecord(alarmVolumeChanged, + optionsAlarmVolumeChanged)); + mImpl.enqueueBroadcastLocked(makeBroadcastRecord(timeTick, optionsTimeTick)); + // Verify that the older timeTick has been removed. + verifyPendingRecords(queue, + List.of(musicVolumeChanged, alarmVolumeChanged, timeTick)); + } + + private void verifyPendingRecords(BroadcastProcessQueue queue, + List<Intent> intents) { + for (int i = 0; i < intents.size(); i++) { + queue.makeActiveNextPending(); + final Intent actualIntent = queue.getActive().intent; + final Intent expectedIntent = intents.get(i); + final String errMsg = "actual=" + actualIntent + ", expected=" + expectedIntent + + ", actual_extras=" + actualIntent.getExtras() + + ", expected_extras=" + expectedIntent.getExtras(); + assertTrue(errMsg, actualIntent.filterEquals(expectedIntent)); + assertTrue(errMsg, Bundle.kindofEquals( + actualIntent.getExtras(), expectedIntent.getExtras())); + } + assertTrue(queue.isEmpty()); + } } diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java index 96707fde8edb..00aa52012e59 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java @@ -176,6 +176,13 @@ public class UserManagerServiceTest { } @Test + public void testHasUserRestriction_NonExistentUserReturnsFalse() { + int nonExistentUserId = UserHandle.USER_NULL; + assertThat(mUserManagerService.hasUserRestriction(DISALLOW_USER_SWITCH, nonExistentUserId)) + .isFalse(); + } + + @Test public void testSetUserRestrictionWithIncorrectID() throws Exception { int incorrectId = 1; while (mUserManagerService.userExists(incorrectId)) { diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java index d5893c8d0b9f..77d542a2e43d 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java @@ -52,7 +52,6 @@ public class DexoptOptionsTests { assertFalse(opt.isBootComplete()); assertFalse(opt.isCheckForProfileUpdates()); assertFalse(opt.isDexoptOnlySecondaryDex()); - assertFalse(opt.isDexoptOnlySharedDex()); assertFalse(opt.isDowngrade()); assertFalse(opt.isForce()); assertFalse(opt.isDexoptIdleBackgroundJob()); @@ -67,7 +66,6 @@ public class DexoptOptionsTests { DexoptOptions.DEXOPT_BOOT_COMPLETE | DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES | DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX | - DexoptOptions.DEXOPT_ONLY_SHARED_DEX | DexoptOptions.DEXOPT_DOWNGRADE | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY | DexoptOptions.DEXOPT_IDLE_BACKGROUND_JOB | @@ -81,7 +79,6 @@ public class DexoptOptionsTests { assertTrue(opt.isBootComplete()); assertTrue(opt.isCheckForProfileUpdates()); assertTrue(opt.isDexoptOnlySecondaryDex()); - assertTrue(opt.isDexoptOnlySharedDex()); assertTrue(opt.isDowngrade()); assertTrue(opt.isForce()); assertTrue(opt.isDexoptAsSharedLibrary()); @@ -113,7 +110,6 @@ public class DexoptOptionsTests { assertTrue(opt.isBootComplete()); assertTrue(opt.isCheckForProfileUpdates()); assertFalse(opt.isDexoptOnlySecondaryDex()); - assertFalse(opt.isDexoptOnlySharedDex()); assertFalse(opt.isDowngrade()); assertTrue(opt.isForce()); assertFalse(opt.isDexoptAsSharedLibrary()); @@ -131,7 +127,6 @@ public class DexoptOptionsTests { assertTrue(opt.isBootComplete()); assertFalse(opt.isCheckForProfileUpdates()); assertFalse(opt.isDexoptOnlySecondaryDex()); - assertFalse(opt.isDexoptOnlySharedDex()); assertFalse(opt.isDowngrade()); assertTrue(opt.isForce()); assertFalse(opt.isDexoptAsSharedLibrary()); diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java index 91c2fe0eb262..8e81e2d8997c 100644 --- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java @@ -1371,6 +1371,39 @@ public class UiModeManagerServiceTest extends UiServiceTestCase { verify(mInjector).startDreamWhenDockedIfAppropriate(mContext); } + @Test + public void dreamWhenDocked_ambientModeSuppressed_suppressionEnabled() { + mUiManagerService.setStartDreamImmediatelyOnDock(true); + mUiManagerService.setDreamsDisabledByAmbientModeSuppression(true); + + when(mLocalPowerManager.isAmbientDisplaySuppressed()).thenReturn(true); + triggerDockIntent(); + verifyAndSendResultBroadcast(); + verify(mInjector, never()).startDreamWhenDockedIfAppropriate(mContext); + } + + @Test + public void dreamWhenDocked_ambientModeSuppressed_suppressionDisabled() { + mUiManagerService.setStartDreamImmediatelyOnDock(true); + mUiManagerService.setDreamsDisabledByAmbientModeSuppression(false); + + when(mLocalPowerManager.isAmbientDisplaySuppressed()).thenReturn(true); + triggerDockIntent(); + verifyAndSendResultBroadcast(); + verify(mInjector).startDreamWhenDockedIfAppropriate(mContext); + } + + @Test + public void dreamWhenDocked_ambientModeNotSuppressed_suppressionEnabled() { + mUiManagerService.setStartDreamImmediatelyOnDock(true); + mUiManagerService.setDreamsDisabledByAmbientModeSuppression(true); + + when(mLocalPowerManager.isAmbientDisplaySuppressed()).thenReturn(false); + triggerDockIntent(); + verifyAndSendResultBroadcast(); + verify(mInjector).startDreamWhenDockedIfAppropriate(mContext); + } + private void triggerDockIntent() { final Intent dockedIntent = new Intent(Intent.ACTION_DOCK_EVENT) diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java index 1e945776cf40..248a3fc8b3b1 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java @@ -15,6 +15,7 @@ */ package com.android.server.notification; +import static android.content.pm.PackageManager.MATCH_ANY_USER; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING; @@ -30,9 +31,11 @@ import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.intThat; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; @@ -49,6 +52,7 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.content.pm.VersionedPackage; +import android.content.res.Resources; import android.os.Bundle; import android.os.UserHandle; import android.service.notification.NotificationListenerFilter; @@ -69,6 +73,7 @@ import com.google.common.collect.ImmutableList; import org.junit.Before; import org.junit.Test; +import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.internal.util.reflection.FieldSetter; @@ -77,6 +82,7 @@ import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.util.Arrays; import java.util.List; public class NotificationListenersTest extends UiServiceTestCase { @@ -85,6 +91,8 @@ public class NotificationListenersTest extends UiServiceTestCase { private PackageManager mPm; @Mock private IPackageManager miPm; + @Mock + private Resources mResources; @Mock NotificationManagerService mNm; @@ -96,7 +104,8 @@ public class NotificationListenersTest extends UiServiceTestCase { private ComponentName mCn1 = new ComponentName("pkg", "pkg.cmp"); private ComponentName mCn2 = new ComponentName("pkg2", "pkg2.cmp2"); - + private ComponentName mUninstalledComponent = new ComponentName("pkg3", + "pkg3.NotificationListenerService"); @Before public void setUp() throws Exception { @@ -111,7 +120,7 @@ public class NotificationListenersTest extends UiServiceTestCase { @Test public void testReadExtraTag() throws Exception { - String xml = "<" + TAG_REQUESTED_LISTENERS+ ">" + String xml = "<" + TAG_REQUESTED_LISTENERS + ">" + "<listener component=\"" + mCn1.flattenToString() + "\" user=\"0\">" + "<allowed types=\"7\" />" + "</listener>" @@ -131,11 +140,55 @@ public class NotificationListenersTest extends UiServiceTestCase { } @Test + public void loadDefaultsFromConfig_forHeadlessSystemUser_loadUninstalled() throws Exception { + // setup with headless system user mode + mListeners = spy(mNm.new NotificationListeners( + mContext, new Object(), mock(ManagedServices.UserProfiles.class), miPm, + /* isHeadlessSystemUserMode= */ true)); + mockDefaultListenerConfigForUninstalledComponent(mUninstalledComponent); + + mListeners.loadDefaultsFromConfig(); + + assertThat(mListeners.getDefaultComponents()).contains(mUninstalledComponent); + } + + @Test + public void loadDefaultsFromConfig_forNonHeadlessSystemUser_ignoreUninstalled() + throws Exception { + // setup without headless system user mode + mListeners = spy(mNm.new NotificationListeners( + mContext, new Object(), mock(ManagedServices.UserProfiles.class), miPm, + /* isHeadlessSystemUserMode= */ false)); + mockDefaultListenerConfigForUninstalledComponent(mUninstalledComponent); + + mListeners.loadDefaultsFromConfig(); + + assertThat(mListeners.getDefaultComponents()).doesNotContain(mUninstalledComponent); + } + + private void mockDefaultListenerConfigForUninstalledComponent(ComponentName componentName) { + ArraySet<ComponentName> components = new ArraySet<>(Arrays.asList(componentName)); + when(mResources + .getString( + com.android.internal.R.string.config_defaultListenerAccessPackages)) + .thenReturn(componentName.getPackageName()); + when(mContext.getResources()).thenReturn(mResources); + doReturn(components).when(mListeners).queryPackageForServices( + eq(componentName.getPackageName()), + intThat(hasIntBitFlag(MATCH_ANY_USER)), + anyInt()); + } + + public static ArgumentMatcher<Integer> hasIntBitFlag(int flag) { + return arg -> arg != null && ((arg & flag) == flag); + } + + @Test public void testWriteExtraTag() throws Exception { NotificationListenerFilter nlf = new NotificationListenerFilter(7, new ArraySet<>()); VersionedPackage a1 = new VersionedPackage("pkg1", 243); NotificationListenerFilter nlf2 = - new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[] {a1})); + new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[]{a1})); mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf); mListeners.setNotificationListenerFilter(Pair.create(mCn2, 10), nlf2); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java index d5e336b1cf2f..eed32d7d815c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java @@ -40,14 +40,18 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.timeout; +import android.app.ActivityOptions; import android.app.WaitResult; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; +import android.os.Binder; import android.os.ConditionVariable; +import android.os.IBinder; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.view.Display; @@ -308,4 +312,40 @@ public class ActivityTaskSupervisorTests extends WindowTestsBase { waitHandlerIdle(mAtm.mH); verify(mRootWindowContainer, timeout(TIMEOUT_MS)).startHomeOnEmptyDisplays("userUnlocked"); } + + /** Verifies that launch from recents sets the launch cookie on the activity. */ + @Test + public void testStartActivityFromRecents_withLaunchCookie() { + final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); + + IBinder launchCookie = new Binder("test_launch_cookie"); + ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchCookie(launchCookie); + SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(options.toBundle()); + + doNothing().when(mSupervisor.mService).moveTaskToFrontLocked(eq(null), eq(null), anyInt(), + anyInt(), any()); + + mSupervisor.startActivityFromRecents(-1, -1, activity.getRootTaskId(), safeOptions); + + assertThat(activity.mLaunchCookie).isEqualTo(launchCookie); + verify(mAtm).moveTaskToFrontLocked(any(), eq(null), anyInt(), anyInt(), eq(safeOptions)); + } + + /** Verifies that launch from recents doesn't set the launch cookie on the activity. */ + @Test + public void testStartActivityFromRecents_withoutLaunchCookie() { + final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); + + SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle( + ActivityOptions.makeBasic().toBundle()); + + doNothing().when(mSupervisor.mService).moveTaskToFrontLocked(eq(null), eq(null), anyInt(), + anyInt(), any()); + + mSupervisor.startActivityFromRecents(-1, -1, activity.getRootTaskId(), safeOptions); + + assertThat(activity.mLaunchCookie).isNull(); + verify(mAtm).moveTaskToFrontLocked(any(), eq(null), anyInt(), anyInt(), eq(safeOptions)); + } } diff --git a/tests/RollbackTest/SampleRollbackApp/AndroidManifest.xml b/tests/RollbackTest/SampleRollbackApp/AndroidManifest.xml index 5a135c978343..7fe4bae2a3fe 100644 --- a/tests/RollbackTest/SampleRollbackApp/AndroidManifest.xml +++ b/tests/RollbackTest/SampleRollbackApp/AndroidManifest.xml @@ -16,7 +16,7 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.sample.rollbackapp" > - <uses-permission android:name="android.permission.TEST_MANAGE_ROLLBACKS" /> + <uses-permission android:name="android.permission.MANAGE_ROLLBACKS" /> <application android:label="@string/title_activity_main"> <activity @@ -28,4 +28,4 @@ </intent-filter> </activity> </application> -</manifest>
\ No newline at end of file +</manifest> diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/PermissionMethodDetector.kt b/tools/lint/checks/src/main/java/com/google/android/lint/PermissionMethodDetector.kt index 68a450d956a8..1b0f03564c3b 100644 --- a/tools/lint/checks/src/main/java/com/google/android/lint/PermissionMethodDetector.kt +++ b/tools/lint/checks/src/main/java/com/google/android/lint/PermissionMethodDetector.kt @@ -26,6 +26,7 @@ import com.android.tools.lint.detector.api.Scope import com.android.tools.lint.detector.api.Severity import com.android.tools.lint.detector.api.SourceCodeScanner import com.android.tools.lint.detector.api.getUMethod +import com.google.android.lint.aidl.hasPermissionMethodAnnotation import com.intellij.psi.PsiType import org.jetbrains.uast.UAnnotation import org.jetbrains.uast.UBlockExpression @@ -149,11 +150,6 @@ class PermissionMethodDetector : Detector(), SourceCodeScanner { enabledByDefault = false ) - private fun hasPermissionMethodAnnotation(method: UMethod): Boolean = method.annotations - .any { - it.hasQualifiedName(ANNOTATION_PERMISSION_METHOD) - } - private fun isPermissionMethodReturnType(method: UMethod): Boolean = listOf(PsiType.VOID, PsiType.INT, PsiType.BOOLEAN).contains(method.returnType) diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionFix.kt b/tools/lint/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionFix.kt index 510611161ea8..d120e1d41c99 100644 --- a/tools/lint/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionFix.kt +++ b/tools/lint/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionFix.kt @@ -18,37 +18,54 @@ package com.google.android.lint.aidl import com.android.tools.lint.detector.api.JavaContext import com.android.tools.lint.detector.api.Location -import com.intellij.psi.PsiVariable +import com.android.tools.lint.detector.api.getUMethod +import org.jetbrains.kotlin.psi.psiUtil.parameterIndex import org.jetbrains.uast.UCallExpression -import org.jetbrains.uast.ULiteralExpression -import org.jetbrains.uast.UQualifiedReferenceExpression -import org.jetbrains.uast.USimpleNameReferenceExpression -import org.jetbrains.uast.asRecursiveLogString +import org.jetbrains.uast.evaluateString +import org.jetbrains.uast.visitor.AbstractUastVisitor /** - * Helper ADT class that facilitates the creation of lint auto fixes + * Helper class that facilitates the creation of lint auto fixes * * Handles "Single" permission checks that should be migrated to @EnforcePermission(...), as well as consecutive checks * that should be migrated to @EnforcePermission(allOf={...}) * * TODO: handle anyOf style annotations */ -sealed class EnforcePermissionFix { - abstract fun locations(): List<Location> - abstract fun javaAnnotationParameter(): String - - fun javaAnnotation(): String = "@$ANNOTATION_ENFORCE_PERMISSION(${javaAnnotationParameter()})" +data class EnforcePermissionFix( + val locations: List<Location>, + val permissionNames: List<String> +) { + val annotation: String + get() { + val quotedPermissions = permissionNames.joinToString(", ") { """"$it"""" } + val annotationParameter = + if (permissionNames.size > 1) "allOf={$quotedPermissions}" else quotedPermissions + return "@$ANNOTATION_ENFORCE_PERMISSION($annotationParameter)" + } companion object { - fun fromCallExpression(callExpression: UCallExpression, context: JavaContext): SingleFix = - SingleFix( - getPermissionCheckLocation(context, callExpression), - getPermissionCheckArgumentValue(callExpression) - ) + /** + * conditionally constructs EnforcePermissionFix from a UCallExpression + * @return EnforcePermissionFix if the called method is annotated with @PermissionMethod, else null + */ + fun fromCallExpression( + context: JavaContext, + callExpression: UCallExpression + ): EnforcePermissionFix? = + if (isPermissionMethodCall(callExpression)) { + EnforcePermissionFix( + listOf(getPermissionCheckLocation(context, callExpression)), + getPermissionCheckValues(callExpression) + ) + } else null - fun maybeAddManifestPrefix(permissionName: String): String = - if (permissionName.contains(".")) permissionName - else "android.Manifest.permission.$permissionName" + + fun compose(individuals: List<EnforcePermissionFix>): EnforcePermissionFix = + EnforcePermissionFix( + individuals.flatMap { it.locations }, + individuals.flatMap { it.permissionNames } + ) /** * Given a permission check, get its proper location @@ -70,49 +87,51 @@ sealed class EnforcePermissionFix { } /** - * Given a permission check and an argument, - * pull out the permission value that is being used + * Given a @PermissionMethod, find arguments annotated with @PermissionName + * and pull out the permission value(s) being used. Also evaluates nested calls + * to @PermissionMethod(s) in the given method's body. */ - private fun getPermissionCheckArgumentValue( - callExpression: UCallExpression, - argumentPosition: Int = 0 - ): String { + private fun getPermissionCheckValues( + callExpression: UCallExpression + ): List<String> { + if (!isPermissionMethodCall(callExpression)) return emptyList() - val identifier = when ( - val argument = callExpression.valueArguments.getOrNull(argumentPosition) - ) { - is UQualifiedReferenceExpression -> when (val selector = argument.selector) { - is USimpleNameReferenceExpression -> - ((selector.resolve() as PsiVariable).computeConstantValue() as String) + val result = mutableSetOf<String>() // protect against duplicate permission values + val visitedCalls = mutableSetOf<UCallExpression>() // don't visit the same call twice + val bfsQueue = ArrayDeque(listOf(callExpression)) - else -> throw RuntimeException( - "Couldn't resolve argument: ${selector.asRecursiveLogString()}" - ) - } + // Breadth First Search - evalutaing nested @PermissionMethod(s) in the available + // source code for @PermissionName(s). + while (bfsQueue.isNotEmpty()) { + val current = bfsQueue.removeFirst() + visitedCalls.add(current) + result.addAll(findPermissions(current)) - is USimpleNameReferenceExpression -> ( - (argument.resolve() as PsiVariable).computeConstantValue() as String) + current.resolve()?.getUMethod()?.accept(object : AbstractUastVisitor() { + override fun visitCallExpression(node: UCallExpression): Boolean { + if (isPermissionMethodCall(node) && node !in visitedCalls) { + bfsQueue.add(node) + } + return false + } + }) + } - is ULiteralExpression -> argument.value as String + return result.toList() + } - else -> throw RuntimeException( - "Couldn't resolve argument: ${argument?.asRecursiveLogString()}" - ) - } + private fun findPermissions( + callExpression: UCallExpression, + ): List<String> { + val indices = callExpression.resolve()?.getUMethod() + ?.uastParameters + ?.filter(::hasPermissionNameAnnotation) + ?.mapNotNull { it.sourcePsi?.parameterIndex() } + ?: emptyList() - return identifier.substringAfterLast(".") + return indices.mapNotNull { + callExpression.getArgumentForParameter(it)?.evaluateString() + } } } } - -data class SingleFix(val location: Location, val permissionName: String) : EnforcePermissionFix() { - override fun locations(): List<Location> = listOf(this.location) - override fun javaAnnotationParameter(): String = maybeAddManifestPrefix(this.permissionName) -} -data class AllOfFix(val checks: List<SingleFix>) : EnforcePermissionFix() { - override fun locations(): List<Location> = this.checks.map { it.location } - override fun javaAnnotationParameter(): String = - "allOf={${ - this.checks.joinToString(", ") { maybeAddManifestPrefix(it.permissionName) } - }}" -} diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt b/tools/lint/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt new file mode 100644 index 000000000000..edbdd8d2adf3 --- /dev/null +++ b/tools/lint/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2022 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.google.android.lint.aidl + +import com.android.tools.lint.detector.api.getUMethod +import com.google.android.lint.ANNOTATION_PERMISSION_METHOD +import com.google.android.lint.ANNOTATION_PERMISSION_NAME +import com.google.android.lint.CLASS_STUB +import com.intellij.psi.PsiAnonymousClass +import org.jetbrains.uast.UCallExpression +import org.jetbrains.uast.UMethod +import org.jetbrains.uast.UParameter + +/** + * Given a UMethod, determine if this method is + * an entrypoint to an interface generated by AIDL, + * returning the interface name if so + */ +fun getContainingAidlInterface(node: UMethod): String? { + if (!isInClassCalledStub(node)) return null + for (superMethod in node.findSuperMethods()) { + for (extendsInterface in superMethod.containingClass?.extendsList?.referenceElements + ?: continue) { + if (extendsInterface.qualifiedName == IINTERFACE_INTERFACE) { + return superMethod.containingClass?.name + } + } + } + return null +} + +private fun isInClassCalledStub(node: UMethod): Boolean { + (node.containingClass as? PsiAnonymousClass)?.let { + return it.baseClassReference.referenceName == CLASS_STUB + } + return node.containingClass?.extendsList?.referenceElements?.any { + it.referenceName == CLASS_STUB + } ?: false +} + +fun isPermissionMethodCall(callExpression: UCallExpression): Boolean { + val method = callExpression.resolve()?.getUMethod() ?: return false + return hasPermissionMethodAnnotation(method) +} + +fun hasPermissionMethodAnnotation(method: UMethod): Boolean = method.annotations + .any { + it.hasQualifiedName(ANNOTATION_PERMISSION_METHOD) + } + +fun hasPermissionNameAnnotation(parameter: UParameter) = parameter.annotations.any { + it.hasQualifiedName(ANNOTATION_PERMISSION_NAME) +} diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/aidl/ManualPermissionCheckDetector.kt b/tools/lint/checks/src/main/java/com/google/android/lint/aidl/ManualPermissionCheckDetector.kt index 2cea39423f1d..2c53f390128c 100644 --- a/tools/lint/checks/src/main/java/com/google/android/lint/aidl/ManualPermissionCheckDetector.kt +++ b/tools/lint/checks/src/main/java/com/google/android/lint/aidl/ManualPermissionCheckDetector.kt @@ -25,9 +25,6 @@ import com.android.tools.lint.detector.api.JavaContext import com.android.tools.lint.detector.api.Scope import com.android.tools.lint.detector.api.Severity import com.android.tools.lint.detector.api.SourceCodeScanner -import com.google.android.lint.CLASS_STUB -import com.google.android.lint.ENFORCE_PERMISSION_METHODS -import com.intellij.psi.PsiAnonymousClass import org.jetbrains.uast.UBlockExpression import org.jetbrains.uast.UCallExpression import org.jetbrains.uast.UElement @@ -56,7 +53,7 @@ class ManualPermissionCheckDetector : Detector(), SourceCodeScanner { val body = (node.uastBody as? UBlockExpression) ?: return val fix = accumulateSimplePermissionCheckFixes(body) ?: return - val javaRemoveFixes = fix.locations().map { + val javaRemoveFixes = fix.locations.map { fix() .replace() .reformat(true) @@ -67,7 +64,7 @@ class ManualPermissionCheckDetector : Detector(), SourceCodeScanner { } val javaAnnotateFix = fix() - .annotate(fix.javaAnnotation()) + .annotate(fix.annotation) .range(context.getLocation(node)) .autoFix() .build() @@ -77,7 +74,7 @@ class ManualPermissionCheckDetector : Detector(), SourceCodeScanner { context.report( ISSUE_USE_ENFORCE_PERMISSION_ANNOTATION, - fix.locations().last(), + fix.locations.last(), message, fix().composite(*javaRemoveFixes.toTypedArray(), javaAnnotateFix) ) @@ -97,14 +94,14 @@ class ManualPermissionCheckDetector : Detector(), SourceCodeScanner { */ private fun accumulateSimplePermissionCheckFixes(methodBody: UBlockExpression): EnforcePermissionFix? { - val singleFixes = mutableListOf<SingleFix>() + val singleFixes = mutableListOf<EnforcePermissionFix>() for (expression in methodBody.expressions) { singleFixes.add(getPermissionCheckFix(expression) ?: break) } return when (singleFixes.size) { 0 -> null 1 -> singleFixes[0] - else -> AllOfFix(singleFixes) + else -> EnforcePermissionFix.compose(singleFixes) } } @@ -113,7 +110,7 @@ class ManualPermissionCheckDetector : Detector(), SourceCodeScanner { * the helper for creating a lint auto fix to @EnforcePermission */ private fun getPermissionCheckFix(startingExpression: UElement?): - SingleFix? { + EnforcePermissionFix? { return when (startingExpression) { is UQualifiedReferenceExpression -> getPermissionCheckFix( startingExpression.selector @@ -121,11 +118,8 @@ class ManualPermissionCheckDetector : Detector(), SourceCodeScanner { is UIfExpression -> getPermissionCheckFix(startingExpression.condition) - is UCallExpression -> { - return if (isPermissionCheck(startingExpression)) - EnforcePermissionFix.fromCallExpression(startingExpression, context) - else null - } + is UCallExpression -> return EnforcePermissionFix + .fromCallExpression(context, startingExpression) else -> null } @@ -160,40 +154,5 @@ class ManualPermissionCheckDetector : Detector(), SourceCodeScanner { ), enabledByDefault = false, // TODO: enable once b/241171714 is resolved ) - - private fun isPermissionCheck(callExpression: UCallExpression): Boolean { - val method = callExpression.resolve() ?: return false - val className = method.containingClass?.qualifiedName - return ENFORCE_PERMISSION_METHODS.any { - it.clazz == className && it.name == method.name - } - } - - /** - * given a UMethod, determine if this method is - * an entrypoint to an interface generated by AIDL, - * returning the interface name if so - */ - fun getContainingAidlInterface(node: UMethod): String? { - if (!isInClassCalledStub(node)) return null - for (superMethod in node.findSuperMethods()) { - for (extendsInterface in superMethod.containingClass?.extendsList?.referenceElements - ?: continue) { - if (extendsInterface.qualifiedName == IINTERFACE_INTERFACE) { - return superMethod.containingClass?.name - } - } - } - return null - } - - private fun isInClassCalledStub(node: UMethod): Boolean { - (node.containingClass as? PsiAnonymousClass)?.let { - return it.baseClassReference.referenceName == CLASS_STUB - } - return node.containingClass?.extendsList?.referenceElements?.any { - it.referenceName == CLASS_STUB - } ?: false - } } } diff --git a/tools/lint/checks/src/test/java/com/google/android/lint/aidl/ManualPermissionCheckDetectorTest.kt b/tools/lint/checks/src/test/java/com/google/android/lint/aidl/ManualPermissionCheckDetectorTest.kt index 1a1c6bc77785..a968f5e6cb1c 100644 --- a/tools/lint/checks/src/test/java/com/google/android/lint/aidl/ManualPermissionCheckDetectorTest.kt +++ b/tools/lint/checks/src/test/java/com/google/android/lint/aidl/ManualPermissionCheckDetectorTest.kt @@ -19,6 +19,7 @@ package com.google.android.lint.aidl import com.android.tools.lint.checks.infrastructure.LintDetectorTest import com.android.tools.lint.checks.infrastructure.TestFile import com.android.tools.lint.checks.infrastructure.TestLintTask +import com.android.tools.lint.checks.infrastructure.TestMode import com.android.tools.lint.detector.api.Detector import com.android.tools.lint.detector.api.Issue @@ -42,7 +43,7 @@ class ManualPermissionCheckDetectorTest : LintDetectorTest() { private Context mContext; @Override public void test() throws android.os.RemoteException { - mContext.enforceCallingOrSelfPermission("android.Manifest.permission.READ_CONTACTS", "foo"); + mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo"); } } """ @@ -53,8 +54,8 @@ class ManualPermissionCheckDetectorTest : LintDetectorTest() { .expect( """ src/Foo.java:7: Warning: ITest permission check can be converted to @EnforcePermission annotation [UseEnforcePermissionAnnotation] - mContext.enforceCallingOrSelfPermission("android.Manifest.permission.READ_CONTACTS", "foo"); - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo"); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 0 errors, 1 warnings """ ) @@ -62,9 +63,9 @@ class ManualPermissionCheckDetectorTest : LintDetectorTest() { """ Fix for src/Foo.java line 7: Annotate with @EnforcePermission: @@ -5 +5 - + @android.annotation.EnforcePermission(android.Manifest.permission.READ_CONTACTS) + + @android.annotation.EnforcePermission("android.permission.READ_CONTACTS") @@ -7 +8 - - mContext.enforceCallingOrSelfPermission("android.Manifest.permission.READ_CONTACTS", "foo"); + - mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo"); """ ) } @@ -81,7 +82,7 @@ class ManualPermissionCheckDetectorTest : LintDetectorTest() { @Override public void test() throws android.os.RemoteException { mContext.enforceCallingOrSelfPermission( - "android.Manifest.permission.READ_CONTACTS", "foo"); + "android.permission.READ_CONTACTS", "foo"); } }; } @@ -102,10 +103,49 @@ class ManualPermissionCheckDetectorTest : LintDetectorTest() { """ Fix for src/Foo.java line 8: Annotate with @EnforcePermission: @@ -6 +6 - + @android.annotation.EnforcePermission(android.Manifest.permission.READ_CONTACTS) + + @android.annotation.EnforcePermission("android.permission.READ_CONTACTS") @@ -8 +9 - mContext.enforceCallingOrSelfPermission( - - "android.Manifest.permission.READ_CONTACTS", "foo"); + - "android.permission.READ_CONTACTS", "foo"); + """ + ) + } + + fun testConstantEvaluation() { + lint().files( + java( + """ + import android.content.Context; + import android.test.ITest; + + public class Foo extends ITest.Stub { + private Context mContext; + @Override + public void test() throws android.os.RemoteException { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_CONTACTS, "foo"); + } + } + """ + ).indented(), + *stubs, + manifestStub + ) + .run() + .expect( + """ + src/Foo.java:8: Warning: ITest permission check can be converted to @EnforcePermission annotation [UseEnforcePermissionAnnotation] + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_CONTACTS, "foo"); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 0 errors, 1 warnings + """ + ) + .expectFixDiffs( + """ + Fix for src/Foo.java line 7: Annotate with @EnforcePermission: + @@ -6 +6 + + @android.annotation.EnforcePermission("android.permission.READ_CONTACTS") + @@ -8 +9 + - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_CONTACTS, "foo"); """ ) } @@ -122,9 +162,9 @@ class ManualPermissionCheckDetectorTest : LintDetectorTest() { @Override public void test() throws android.os.RemoteException { mContext.enforceCallingOrSelfPermission( - "android.Manifest.permission.READ_CONTACTS", "foo"); + "android.permission.READ_CONTACTS", "foo"); mContext.enforceCallingOrSelfPermission( - "android.Manifest.permission.WRITE_CONTACTS", "foo"); + "android.permission.WRITE_CONTACTS", "foo"); } }; } @@ -144,13 +184,13 @@ class ManualPermissionCheckDetectorTest : LintDetectorTest() { .expectFixDiffs( """ Fix for src/Foo.java line 10: Annotate with @EnforcePermission: - @@ -6 +6 - + @android.annotation.EnforcePermission(allOf={android.Manifest.permission.READ_CONTACTS, android.Manifest.permission.WRITE_CONTACTS}) + @@ -6 +6 + + @android.annotation.EnforcePermission(allOf={"android.permission.READ_CONTACTS", "android.permission.WRITE_CONTACTS"}) @@ -8 +9 - mContext.enforceCallingOrSelfPermission( - - "android.Manifest.permission.READ_CONTACTS", "foo"); + - "android.permission.READ_CONTACTS", "foo"); - mContext.enforceCallingOrSelfPermission( - - "android.Manifest.permission.WRITE_CONTACTS", "foo"); + - "android.permission.WRITE_CONTACTS", "foo"); """ ) } @@ -166,7 +206,7 @@ class ManualPermissionCheckDetectorTest : LintDetectorTest() { @Override public void test() throws android.os.RemoteException { long uid = Binder.getCallingUid(); - mContext.enforceCallingOrSelfPermission("android.Manifest.permission.READ_CONTACTS", "foo"); + mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo"); } } """ @@ -177,6 +217,149 @@ class ManualPermissionCheckDetectorTest : LintDetectorTest() { .expectClean() } + fun testPermissionHelper() { + lint().skipTestModes(TestMode.PARENTHESIZED).files( + java( + """ + import android.content.Context; + import android.test.ITest; + + public class Foo extends ITest.Stub { + private Context mContext; + + @android.content.pm.PermissionMethod + private void helper() { + mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo"); + } + + @Override + public void test() throws android.os.RemoteException { + helper(); + } + } + """ + ).indented(), + *stubs + ) + .run() + .expect( + """ + src/Foo.java:14: Warning: ITest permission check can be converted to @EnforcePermission annotation [UseEnforcePermissionAnnotation] + helper(); + ~~~~~~~~~ + 0 errors, 1 warnings + """ + ) + .expectFixDiffs( + """ + Fix for src/Foo.java line 14: Annotate with @EnforcePermission: + @@ -12 +12 + + @android.annotation.EnforcePermission("android.permission.READ_CONTACTS") + @@ -14 +15 + - helper(); + """ + ) + } + + fun testPermissionHelperAllOf() { + lint().skipTestModes(TestMode.PARENTHESIZED).files( + java( + """ + import android.content.Context; + import android.test.ITest; + + public class Foo extends ITest.Stub { + private Context mContext; + + @android.content.pm.PermissionMethod + private void helper() { + mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo"); + mContext.enforceCallingOrSelfPermission("android.permission.WRITE_CONTACTS", "foo"); + } + + @Override + public void test() throws android.os.RemoteException { + helper(); + mContext.enforceCallingOrSelfPermission("FOO", "foo"); + } + } + """ + ).indented(), + *stubs + ) + .run() + .expect( + """ + src/Foo.java:16: Warning: ITest permission check can be converted to @EnforcePermission annotation [UseEnforcePermissionAnnotation] + mContext.enforceCallingOrSelfPermission("FOO", "foo"); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 0 errors, 1 warnings + """ + ) + .expectFixDiffs( + """ + Fix for src/Foo.java line 16: Annotate with @EnforcePermission: + @@ -13 +13 + + @android.annotation.EnforcePermission(allOf={"android.permission.READ_CONTACTS", "android.permission.WRITE_CONTACTS", "FOO"}) + @@ -15 +16 + - helper(); + - mContext.enforceCallingOrSelfPermission("FOO", "foo"); + """ + ) + } + + + fun testPermissionHelperNested() { + lint().skipTestModes(TestMode.PARENTHESIZED).files( + java( + """ + import android.content.Context; + import android.test.ITest; + + public class Foo extends ITest.Stub { + private Context mContext; + + @android.content.pm.PermissionMethod + private void helperHelper() { + helper("android.permission.WRITE_CONTACTS"); + } + + @android.content.pm.PermissionMethod + private void helper(@android.content.pm.PermissionName String extraPermission) { + mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo"); + } + + @Override + public void test() throws android.os.RemoteException { + helperHelper(); + } + } + """ + ).indented(), + *stubs + ) + .run() + .expect( + """ + src/Foo.java:19: Warning: ITest permission check can be converted to @EnforcePermission annotation [UseEnforcePermissionAnnotation] + helperHelper(); + ~~~~~~~~~~~~~~~ + 0 errors, 1 warnings + """ + ) + .expectFixDiffs( + """ + Fix for src/Foo.java line 19: Annotate with @EnforcePermission: + @@ -17 +17 + + @android.annotation.EnforcePermission(allOf={"android.permission.WRITE_CONTACTS", "android.permission.READ_CONTACTS"}) + @@ -19 +20 + - helperHelper(); + """ + ) + } + + + companion object { private val aidlStub: TestFile = java( """ @@ -192,7 +375,8 @@ class ManualPermissionCheckDetectorTest : LintDetectorTest() { """ package android.content; public class Context { - public void enforceCallingOrSelfPermission(String permission, String message) {} + @android.content.pm.PermissionMethod + public void enforceCallingOrSelfPermission(@android.content.pm.PermissionName String permission, String message) {} } """ ).indented() @@ -206,6 +390,59 @@ class ManualPermissionCheckDetectorTest : LintDetectorTest() { """ ).indented() - val stubs = arrayOf(aidlStub, contextStub, binderStub) + private val permissionMethodStub: TestFile = java( + """ + package android.content.pm; + + import static java.lang.annotation.ElementType.METHOD; + import static java.lang.annotation.RetentionPolicy.CLASS; + + import java.lang.annotation.Retention; + import java.lang.annotation.Target; + + @Retention(CLASS) + @Target({METHOD}) + public @interface PermissionMethod {} + """ + ).indented() + + private val permissionNameStub: TestFile = java( + """ + package android.content.pm; + + import static java.lang.annotation.ElementType.FIELD; + import static java.lang.annotation.ElementType.LOCAL_VARIABLE; + import static java.lang.annotation.ElementType.METHOD; + import static java.lang.annotation.ElementType.PARAMETER; + import static java.lang.annotation.RetentionPolicy.CLASS; + + import java.lang.annotation.Retention; + import java.lang.annotation.Target; + + @Retention(CLASS) + @Target({PARAMETER, METHOD, LOCAL_VARIABLE, FIELD}) + public @interface PermissionName {} + """ + ).indented() + + private val manifestStub: TestFile = java( + """ + package android; + + public final class Manifest { + public static final class permission { + public static final String READ_CONTACTS="android.permission.READ_CONTACTS"; + } + } + """.trimIndent() + ) + + val stubs = arrayOf( + aidlStub, + contextStub, + binderStub, + permissionMethodStub, + permissionNameStub + ) } } |