diff options
184 files changed, 2605 insertions, 1566 deletions
diff --git a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java index 971c0caced30..a1383e620616 100644 --- a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java +++ b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java @@ -306,10 +306,9 @@ public class ImePerfTest extends ImePerfTestBase while (state.keepRunning(measuredTimeNs)) { setImeListener(activity, latchStart, latchEnd); - latchStart.set(new CountDownLatch(show ? 1 : 2)); - latchEnd.set(new CountDownLatch(2)); // For measuring hide, lets show IME first. if (!show) { + initLatch(latchStart, latchEnd); AtomicBoolean showCalled = new AtomicBoolean(); getInstrumentation().runOnMainSync(() -> { if (!isImeVisible(activity)) { @@ -318,9 +317,10 @@ public class ImePerfTest extends ImePerfTestBase } }); if (showCalled.get()) { - PollingCheck.check("IME show animation should finish ", TIMEOUT_1_S_IN_MS, - () -> latchStart.get().getCount() == 1 - && latchEnd.get().getCount() == 1); + PollingCheck.check("IME show animation should finish ", + TIMEOUT_1_S_IN_MS * 3, + () -> latchStart.get().getCount() == 0 + && latchEnd.get().getCount() == 0); } } if (!mIsTraceStarted && !state.isWarmingUp()) { @@ -330,6 +330,7 @@ public class ImePerfTest extends ImePerfTestBase AtomicLong startTime = new AtomicLong(); AtomicBoolean unexpectedVisibility = new AtomicBoolean(); + initLatch(latchStart, latchEnd); getInstrumentation().runOnMainSync(() -> { boolean isVisible = isImeVisible(activity); startTime.set(SystemClock.elapsedRealtimeNanos()); @@ -348,11 +349,15 @@ public class ImePerfTest extends ImePerfTestBase long timeElapsed = waitForAnimationStart(latchStart, startTime); if (timeElapsed != ANIMATION_NOT_STARTED) { measuredTimeNs = timeElapsed; + // wait for animation to end or we may start two animations and timing + // will not be measured accurately. + waitForAnimationEnd(latchEnd); } } // hide IME before next iteration. if (show) { + initLatch(latchStart, latchEnd); activity.runOnUiThread(() -> controller.hide(WindowInsets.Type.ime())); try { latchEnd.get().await(TIMEOUT_1_S_IN_MS * 5, TimeUnit.MILLISECONDS); @@ -374,6 +379,12 @@ public class ImePerfTest extends ImePerfTestBase addResultToState(state); } + private void initLatch(AtomicReference<CountDownLatch> latchStart, + AtomicReference<CountDownLatch> latchEnd) { + latchStart.set(new CountDownLatch(1)); + latchEnd.set(new CountDownLatch(1)); + } + @UiThread private boolean isImeVisible(@NonNull final Activity activity) { return activity.getWindow().getDecorView().getRootWindowInsets().isVisible( @@ -383,7 +394,7 @@ public class ImePerfTest extends ImePerfTestBase private long waitForAnimationStart( AtomicReference<CountDownLatch> latchStart, AtomicLong startTime) { try { - latchStart.get().await(TIMEOUT_1_S_IN_MS * 5, TimeUnit.MILLISECONDS); + latchStart.get().await(5, TimeUnit.SECONDS); if (latchStart.get().getCount() != 0) { return ANIMATION_NOT_STARTED; } @@ -392,6 +403,12 @@ public class ImePerfTest extends ImePerfTestBase return SystemClock.elapsedRealtimeNanos() - startTime.get(); } + private void waitForAnimationEnd(AtomicReference<CountDownLatch> latchEnd) { + try { + latchEnd.get().await(3, TimeUnit.SECONDS); + } catch (InterruptedException e) { } + } + private void addResultToState(ManualBenchmarkState state) { mTraceMethods.forAllSlices((key, slices) -> { for (TraceMarkSlice slice : slices) { diff --git a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java index 0b5ff1b9e5d8..f08dd24b3841 100644 --- a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java +++ b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java @@ -311,6 +311,8 @@ public abstract class EconomicPolicy { case AlarmManagerEconomicPolicy.ACTION_ALARM_CLOCK: return "ALARM_CLOCK"; } + break; + case POLICY_JS: switch (eventId) { case JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START: @@ -336,6 +338,7 @@ public abstract class EconomicPolicy { case JobSchedulerEconomicPolicy.ACTION_JOB_TIMEOUT: return "JOB_TIMEOUT"; } + break; } return "UNKNOWN_ACTION:" + Integer.toHexString(eventId); } diff --git a/core/api/current.txt b/core/api/current.txt index 894a894967cc..69c94391240d 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -30831,7 +30831,7 @@ package android.os { field public static final int Q = 29; // 0x1d field public static final int R = 30; // 0x1e field public static final int S = 31; // 0x1f - field public static final int T = 10000; // 0x2710 + field public static final int TIRAMISU = 10000; // 0x2710 } public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 0d15a03824ca..78e899fd54b9 100644..100755 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -924,6 +924,7 @@ package android.app.admin { } public class DevicePolicyManager { + method @Nullable public android.content.Intent createProvisioningIntentFromNfcIntent(@NonNull android.content.Intent); method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean getBluetoothContactSharingDisabled(@NonNull android.os.UserHandle); method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwner(); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, "android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"}) public android.content.ComponentName getDeviceOwnerComponentOnAnyUser(); @@ -972,6 +973,7 @@ package android.app.admin { field public static final int FLAG_SUPPORTED_MODES_PERSONALLY_OWNED = 2; // 0x2 field public static final int PROVISIONING_TRIGGER_CLOUD_ENROLLMENT = 1; // 0x1 field public static final int PROVISIONING_TRIGGER_MANAGED_ACCOUNT = 4; // 0x4 + field public static final int PROVISIONING_TRIGGER_NFC = 5; // 0x5 field @Deprecated public static final int PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER = 3; // 0x3 field public static final int PROVISIONING_TRIGGER_QR_CODE = 2; // 0x2 field public static final int PROVISIONING_TRIGGER_UNSPECIFIED = 0; // 0x0 diff --git a/core/api/test-current.txt b/core/api/test-current.txt index e00c16da817c..fb481eb319d5 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -3272,8 +3272,8 @@ package android.window { public class WindowOrganizer { ctor public WindowOrganizer(); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public int applySyncTransaction(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.WindowContainerTransactionCallback); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void applyTransaction(@NonNull android.window.WindowContainerTransaction); + method @RequiresPermission(value=android.Manifest.permission.MANAGE_ACTIVITY_TASKS, conditional=true) public int applySyncTransaction(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.WindowContainerTransactionCallback); + method @RequiresPermission(value=android.Manifest.permission.MANAGE_ACTIVITY_TASKS, conditional=true) public void applyTransaction(@NonNull android.window.WindowContainerTransaction); } @UiContext public abstract class WindowProviderService extends android.app.Service { diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 7e5b5a677efe..2c38688fe685 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -56,6 +56,7 @@ import android.graphics.Bitmap; import android.net.PrivateDnsConnectivityChecker; import android.net.ProxyInfo; import android.net.Uri; +import android.nfc.NfcAdapter; import android.os.Build; import android.os.Bundle; import android.os.ParcelFileDescriptor; @@ -1216,7 +1217,8 @@ public class DevicePolicyManager { PROVISIONING_TRIGGER_CLOUD_ENROLLMENT, PROVISIONING_TRIGGER_QR_CODE, PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER, - PROVISIONING_TRIGGER_MANAGED_ACCOUNT + PROVISIONING_TRIGGER_MANAGED_ACCOUNT, + PROVISIONING_TRIGGER_NFC }) @Retention(RetentionPolicy.SOURCE) public @interface ProvisioningTrigger {} @@ -1254,6 +1256,7 @@ public class DevicePolicyManager { * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT * @see #PROVISIONING_TRIGGER_QR_CODE * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT + * @see #PROVISIONING_TRIGGER_NFC * @hide */ @SystemApi @@ -1265,6 +1268,7 @@ public class DevicePolicyManager { * @see #PROVISIONING_TRIGGER_QR_CODE * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT * @see #PROVISIONING_TRIGGER_UNSPECIFIED + * @see #PROVISIONING_TRIGGER_NFC * @hide */ @SystemApi @@ -1276,6 +1280,7 @@ public class DevicePolicyManager { * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT * @see #PROVISIONING_TRIGGER_UNSPECIFIED + * @see #PROVISIONING_TRIGGER_NFC * @hide */ @SystemApi @@ -1295,6 +1300,7 @@ public class DevicePolicyManager { * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT * @see #PROVISIONING_TRIGGER_QR_CODE * @see #PROVISIONING_TRIGGER_UNSPECIFIED + * @see #PROVISIONING_TRIGGER_NFC * @hide */ @SystemApi @@ -1308,12 +1314,25 @@ public class DevicePolicyManager { * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT * @see #PROVISIONING_TRIGGER_QR_CODE * @see #PROVISIONING_TRIGGER_UNSPECIFIED + * @see #PROVISIONING_TRIGGER_NFC * @hide */ @SystemApi public static final int PROVISIONING_TRIGGER_MANAGED_ACCOUNT = 4; /** + * A value for {@link #EXTRA_PROVISIONING_TRIGGER} indicating that the provisioning is + * triggered by tapping an NFC tag. + * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT + * @see #PROVISIONING_TRIGGER_QR_CODE + * @see #PROVISIONING_TRIGGER_UNSPECIFIED + * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT + * @hide + */ + @SystemApi + public static final int PROVISIONING_TRIGGER_NFC = 5; + + /** * Flag for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that provisioning is * organization-owned. * @@ -14009,4 +14028,33 @@ public class DevicePolicyManager { throw e.rethrowFromSystemServer(); } } + + /** + * Creates a {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} intent + * from the provided {@code nfcIntent}. + * + * <p>Prerequisites to create the provisioning intent: + * + * <ul> + * <li>{@code nfcIntent}'s action is {@link NfcAdapter#ACTION_NDEF_DISCOVERED}</li> + * <li>{@code nfcIntent}'s NFC properties contain either + * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} or + * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} </li> + * </ul> + * + * This method returns {@code null} if the prerequisites are not met or if an error occurs + * when reading the NFC properties. + * + * @param nfcIntent the nfc intent generated from scanning a NFC tag + * @return a {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} intent with + * intent extras as read by {@code nfcIntent}'s NFC properties or {@code null} if the + * prerequisites are not met or if an error occurs when reading the NFC properties. + * + * @hide + */ + @Nullable + @SystemApi + public Intent createProvisioningIntentFromNfcIntent(@NonNull Intent nfcIntent) { + return ProvisioningIntentHelper.createProvisioningIntentFromNfcIntent(nfcIntent); + } } diff --git a/core/java/android/app/admin/ProvisioningIntentHelper.java b/core/java/android/app/admin/ProvisioningIntentHelper.java new file mode 100644 index 000000000000..fbad90c30d7e --- /dev/null +++ b/core/java/android/app/admin/ProvisioningIntentHelper.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.admin; + +import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE; +import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME; +import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME; +import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TRIGGER; +import static android.app.admin.DevicePolicyManager.MIME_TYPE_PROVISIONING_NFC; +import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_NFC; +import static android.nfc.NfcAdapter.EXTRA_NDEF_MESSAGES; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.util.Objects.requireNonNull; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.content.Intent; +import android.nfc.NdefMessage; +import android.nfc.NdefRecord; +import android.nfc.NfcAdapter; +import android.os.Bundle; +import android.os.Parcelable; +import android.util.Log; + +import java.io.IOException; +import java.io.StringReader; +import java.util.Enumeration; +import java.util.Properties; + +/** + * Utility class that provides functionality to create provisioning intents from nfc intents. + */ +final class ProvisioningIntentHelper { + + private static final String TAG = "ProvisioningIntentHelper"; + + /** + * This class is never instantiated + */ + private ProvisioningIntentHelper() { } + + @Nullable + public static Intent createProvisioningIntentFromNfcIntent(@NonNull Intent nfcIntent) { + requireNonNull(nfcIntent); + + if (!NfcAdapter.ACTION_NDEF_DISCOVERED.equals(nfcIntent.getAction())) { + Log.e(TAG, "Wrong Nfc action: " + nfcIntent.getAction()); + return null; + } + + NdefRecord firstRecord = getFirstNdefRecord(nfcIntent); + + if (firstRecord != null) { + return createProvisioningIntentFromNdefRecord(firstRecord); + } + + return null; + } + + + private static Intent createProvisioningIntentFromNdefRecord(NdefRecord firstRecord) { + requireNonNull(firstRecord); + + Properties properties = loadPropertiesFromPayload(firstRecord.getPayload()); + + if (properties == null) { + Log.e(TAG, "Failed to load NdefRecord properties."); + return null; + } + + Bundle bundle = createBundleFromProperties(properties); + + if (!containsRequiredProvisioningExtras(bundle)) { + Log.e(TAG, "Bundle does not contain the required provisioning extras."); + return null; + } + + return createProvisioningIntentFromBundle(bundle); + } + + private static Properties loadPropertiesFromPayload(byte[] payload) { + Properties properties = new Properties(); + + try { + properties.load(new StringReader(new String(payload, UTF_8))); + } catch (IOException e) { + Log.e(TAG, "NFC Intent properties loading failed."); + return null; + } + + return properties; + } + + private static Bundle createBundleFromProperties(Properties properties) { + Enumeration propertyNames = properties.propertyNames(); + Bundle bundle = new Bundle(); + + while (propertyNames.hasMoreElements()) { + String propertyName = (String) propertyNames.nextElement(); + addPropertyToBundle(propertyName, properties, bundle); + } + return bundle; + } + + private static void addPropertyToBundle( + String propertyName, Properties properties, Bundle bundle) { + if(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME.equals(propertyName)) { + ComponentName componentName = ComponentName.unflattenFromString( + properties.getProperty(propertyName)); + bundle.putParcelable(propertyName, componentName); + } + else { + bundle.putString(propertyName, properties.getProperty(propertyName)); + } + } + + private static Intent createProvisioningIntentFromBundle(Bundle bundle) { + requireNonNull(bundle); + + Intent provisioningIntent = new Intent(ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE); + + provisioningIntent.putExtras(bundle); + + provisioningIntent.putExtra(EXTRA_PROVISIONING_TRIGGER, PROVISIONING_TRIGGER_NFC); + + return provisioningIntent; + } + + private static boolean containsRequiredProvisioningExtras(Bundle bundle) { + return bundle.containsKey(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME) || + bundle.containsKey(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME); + } + + /** + * Returns the first {@link NdefRecord} found with a recognized MIME-type + */ + private static NdefRecord getFirstNdefRecord(Intent nfcIntent) { + Parcelable[] ndefMessages = nfcIntent.getParcelableArrayExtra(EXTRA_NDEF_MESSAGES); + if (ndefMessages == null) { + Log.i(TAG, "No EXTRA_NDEF_MESSAGES from nfcIntent"); + return null; + } + + for (Parcelable rawMsg : ndefMessages) { + NdefMessage msg = (NdefMessage) rawMsg; + for (NdefRecord record : msg.getRecords()) { + String mimeType = new String(record.getType(), UTF_8); + + // Only one first message with NFC_MIME_TYPE is used. + if (MIME_TYPE_PROVISIONING_NFC.equals(mimeType)) { + return record; + } + + // Assume only first record of message is used. + break; + } + } + + Log.i(TAG, "No compatible records found on nfcIntent"); + return null; + } +} diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java index 9af0e09ee97a..3184c71042be 100644 --- a/core/java/android/hardware/location/ContextHubManager.java +++ b/core/java/android/hardware/location/ContextHubManager.java @@ -931,6 +931,9 @@ public final class ContextHubManager { * on the provided PendingIntent, then the client will be automatically unregistered by the * service. * + * Note that the {@link PendingIntent} supplied to this API must be mutable for Intent + * notifications to work. + * * @param context the context of the application. If a PendingIntent client is recreated, * the latest state in the context will be used and old state will be discarded * @param hubInfo the hub to attach this client to @@ -938,7 +941,8 @@ public final class ContextHubManager { * @param nanoAppId the ID of the nanoapp that Intent events will be generated for * @return the registered client object * - * @throws IllegalArgumentException if hubInfo does not represent a valid hub + * @throws IllegalArgumentException if hubInfo does not represent a valid hub, or an immutable + * PendingIntent was supplied * @throws IllegalStateException if there were too many registered clients at the service * @throws NullPointerException if pendingIntent or hubInfo is null */ @@ -951,6 +955,9 @@ public final class ContextHubManager { @NonNull PendingIntent pendingIntent, long nanoAppId) { Objects.requireNonNull(pendingIntent); Objects.requireNonNull(hubInfo); + if (pendingIntent.isImmutable()) { + throw new IllegalArgumentException("PendingIntent must be mutable"); + } ContextHubClient client = new ContextHubClient(hubInfo, true /* persistent */); diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index f7b1525569fd..394d270e1e51 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -1132,9 +1132,9 @@ public class Build { public static final int S = 31; /** - * T. + * Tiramisu. */ - public static final int T = CUR_DEVELOPMENT; + public static final int TIRAMISU = CUR_DEVELOPMENT; } /** The type of build, like "user" or "eng". */ diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 1793eaf2ec57..f3ebe5bfec7c 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -10079,9 +10079,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); - ViewStructure child = structure.newChild(i); - populateVirtualStructure(child, provider, cinfo, forAutofill); - cinfo.recycle(); + if (cinfo != null) { + ViewStructure child = structure.newChild(i); + populateVirtualStructure(child, provider, cinfo, forAutofill); + cinfo.recycle(); + } } } } diff --git a/core/java/android/window/DisplayAreaOrganizer.java b/core/java/android/window/DisplayAreaOrganizer.java index e6746556fb67..6758a3b411a2 100644 --- a/core/java/android/window/DisplayAreaOrganizer.java +++ b/core/java/android/window/DisplayAreaOrganizer.java @@ -265,6 +265,7 @@ public class DisplayAreaOrganizer extends WindowOrganizer { } }; + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) private IDisplayAreaOrganizerController getController() { try { return getWindowOrganizerController().getDisplayAreaOrganizerController(); @@ -272,5 +273,4 @@ public class DisplayAreaOrganizer extends WindowOrganizer { return null; } } - } diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java index 3b4d4e52c908..b252df7c72e9 100644 --- a/core/java/android/window/TaskFragmentOrganizer.java +++ b/core/java/android/window/TaskFragmentOrganizer.java @@ -120,6 +120,19 @@ public class TaskFragmentOrganizer extends WindowOrganizer { public void onTaskFragmentError( @NonNull IBinder errorCallbackToken, @NonNull Throwable exception) {} + @Override + public void applyTransaction(@NonNull WindowContainerTransaction t) { + t.setTaskFragmentOrganizer(mInterface); + super.applyTransaction(t); + } + + @Override + public int applySyncTransaction(@NonNull WindowContainerTransaction t, + @NonNull WindowContainerTransactionCallback callback) { + t.setTaskFragmentOrganizer(mInterface); + return super.applySyncTransaction(t, callback); + } + private final ITaskFragmentOrganizer mInterface = new ITaskFragmentOrganizer.Stub() { @Override public void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentInfo) { diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java index 8fa011028f44..6f250fc0ce7a 100644 --- a/core/java/android/window/TaskOrganizer.java +++ b/core/java/android/window/TaskOrganizer.java @@ -290,6 +290,7 @@ public class TaskOrganizer extends WindowOrganizer { } }; + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) private ITaskOrganizerController getController() { try { return getWindowOrganizerController().getTaskOrganizerController(); diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index 9c512add3345..8735ed841ebc 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -35,6 +35,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Objects; /** * Represents a collection of operations on some WindowContainers that should be applied all at @@ -52,12 +53,16 @@ public final class WindowContainerTransaction implements Parcelable { @Nullable private IBinder mErrorCallbackToken; + @Nullable + private ITaskFragmentOrganizer mTaskFragmentOrganizer; + public WindowContainerTransaction() {} private WindowContainerTransaction(Parcel in) { in.readMap(mChanges, null /* loader */); in.readList(mHierarchyOps, null /* loader */); mErrorCallbackToken = in.readStrongBinder(); + mTaskFragmentOrganizer = ITaskFragmentOrganizer.Stub.asInterface(in.readStrongBinder()); } private Change getOrCreateChange(IBinder token) { @@ -473,7 +478,7 @@ public final class WindowContainerTransaction implements Parcelable { final HierarchyOp hierarchyOp = new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_CHILDREN) .setContainer(oldParent.asBinder()) - .setReparentContainer(newParent.asBinder()) + .setReparentContainer(newParent != null ? newParent.asBinder() : null) .build(); mHierarchyOps.add(hierarchyOp); return this; @@ -497,6 +502,23 @@ public final class WindowContainerTransaction implements Parcelable { } /** + * Sets the {@link TaskFragmentOrganizer} that applies this {@link WindowContainerTransaction}. + * When this is set, the server side will not check for the permission of + * {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS}, but will ensure this WCT only + * contains operations that are allowed for this organizer, such as modifying TaskFragments that + * are organized by this organizer. + * @hide + */ + @NonNull + WindowContainerTransaction setTaskFragmentOrganizer(@NonNull ITaskFragmentOrganizer organizer) { + if (mTaskFragmentOrganizer != null) { + throw new IllegalStateException("Can't set multiple organizers for one transaction."); + } + mTaskFragmentOrganizer = organizer; + return this; + } + + /** * Merges another WCT into this one. * @param transfer When true, this will transfer everything from other potentially leaving * other in an unusable state. When false, other is left alone, but @@ -519,7 +541,17 @@ public final class WindowContainerTransaction implements Parcelable { } if (mErrorCallbackToken != null && other.mErrorCallbackToken != null && mErrorCallbackToken != other.mErrorCallbackToken) { - throw new IllegalArgumentException("Can't merge two WCT with different error token"); + throw new IllegalArgumentException("Can't merge two WCTs with different error token"); + } + final IBinder taskFragmentOrganizerAsBinder = mTaskFragmentOrganizer != null + ? mTaskFragmentOrganizer.asBinder() + : null; + final IBinder otherTaskFragmentOrganizerAsBinder = other.mTaskFragmentOrganizer != null + ? other.mTaskFragmentOrganizer.asBinder() + : null; + if (!Objects.equals(taskFragmentOrganizerAsBinder, otherTaskFragmentOrganizerAsBinder)) { + throw new IllegalArgumentException( + "Can't merge two WCTs from different TaskFragmentOrganizers"); } mErrorCallbackToken = mErrorCallbackToken != null ? mErrorCallbackToken @@ -547,11 +579,21 @@ public final class WindowContainerTransaction implements Parcelable { return mErrorCallbackToken; } + /** @hide */ + @Nullable + public ITaskFragmentOrganizer getTaskFragmentOrganizer() { + return mTaskFragmentOrganizer; + } + @Override @NonNull public String toString() { - return "WindowContainerTransaction { changes = " + mChanges + " hops = " + mHierarchyOps - + " errorCallbackToken=" + mErrorCallbackToken + " }"; + return "WindowContainerTransaction {" + + " changes = " + mChanges + + " hops = " + mHierarchyOps + + " errorCallbackToken=" + mErrorCallbackToken + + " taskFragmentOrganizer=" + mTaskFragmentOrganizer + + " }"; } @Override @@ -560,6 +602,7 @@ public final class WindowContainerTransaction implements Parcelable { dest.writeMap(mChanges); dest.writeList(mHierarchyOps); dest.writeStrongBinder(mErrorCallbackToken); + dest.writeStrongInterface(mTaskFragmentOrganizer); } @Override diff --git a/core/java/android/window/WindowOrganizer.java b/core/java/android/window/WindowOrganizer.java index 544d42240079..78dbebaf2738 100644 --- a/core/java/android/window/WindowOrganizer.java +++ b/core/java/android/window/WindowOrganizer.java @@ -36,9 +36,16 @@ public class WindowOrganizer { /** * Apply multiple WindowContainer operations at once. + * + * Note that using this API requires the caller to hold + * {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS}, unless the caller is using + * {@link TaskFragmentOrganizer}, in which case it is allowed to change TaskFragment that is + * created by itself. + * * @param t The transaction to apply. */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) + @RequiresPermission(value = android.Manifest.permission.MANAGE_ACTIVITY_TASKS, + conditional = true) public void applyTransaction(@NonNull WindowContainerTransaction t) { try { if (!t.isEmpty()) { @@ -51,6 +58,12 @@ public class WindowOrganizer { /** * Apply multiple WindowContainer operations at once. + * + * Note that using this API requires the caller to hold + * {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS}, unless the caller is using + * {@link TaskFragmentOrganizer}, in which case it is allowed to change TaskFragment that is + * created by itself. + * * @param t The transaction to apply. * @param callback This transaction will use the synchronization scheme described in * BLASTSyncEngine.java. The SurfaceControl transaction containing the effects of this @@ -58,7 +71,8 @@ public class WindowOrganizer { * @return An ID for the sync operation which will later be passed to transactionReady callback. * This lets the caller differentiate overlapping sync operations. */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) + @RequiresPermission(value = android.Manifest.permission.MANAGE_ACTIVITY_TASKS, + conditional = true) public int applySyncTransaction(@NonNull WindowContainerTransaction t, @NonNull WindowContainerTransactionCallback callback) { try { @@ -123,7 +137,6 @@ public class WindowOrganizer { } } - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) IWindowOrganizerController getWindowOrganizerController() { return IWindowOrganizerControllerSingleton.get(); } diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 1d07c26de17a..e2745959e15d 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -311,6 +311,7 @@ cc_library_shared { header_libs: [ "bionic_libc_platform_headers", "dnsproxyd_protocol_headers", + "libandroid_runtime_vm_headers", ], }, host: { @@ -386,3 +387,29 @@ cc_library_shared { never: true, }, } + +cc_library_headers { + name: "libandroid_runtime_vm_headers", + host_supported: true, + vendor_available: true, + // TODO(b/153609531): remove when libbinder is not native_bridge_supported + native_bridge_supported: true, + // Allow only modules from the following list to create threads that can be + // attached to the JVM. This list should be a subset of the dependencies of + // libandroid_runtime. + visibility: [ + "//frameworks/native/libs/binder", + ], + export_include_dirs: ["include_vm"], + header_libs: [ + "jni_headers", + ], + export_header_lib_headers: [ + "jni_headers", + ], + apex_available: [ + "//apex_available:platform", + "com.android.media", + "com.android.media.swcodec", + ], +} diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 406ccde53330..09d7ef0181a5 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -22,6 +22,7 @@ #include <android-base/properties.h> #include <android/graphics/jni_runtime.h> #include <android_runtime/AndroidRuntime.h> +#include <android_runtime/vm.h> #include <assert.h> #include <binder/IBinder.h> #include <binder/IPCThreadState.h> @@ -1331,6 +1332,10 @@ void AndroidRuntime::onVmCreated(JNIEnv* env) return AndroidRuntime::mJavaVM; } +extern "C" JavaVM* AndroidRuntimeGetJavaVM() { + return AndroidRuntime::getJavaVM(); +} + /* * Get the JNIEnv pointer for this thread. * diff --git a/core/jni/include_vm/android_runtime/vm.h b/core/jni/include_vm/android_runtime/vm.h new file mode 100644 index 000000000000..a6e7c162d6ed --- /dev/null +++ b/core/jni/include_vm/android_runtime/vm.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <jni.h> + +// Get the Java VM. If the symbol doesn't exist at runtime, it means libandroid_runtime +// is not loaded in the current process. If the symbol exists but it returns nullptr, it +// means JavaVM is not yet started. +extern "C" JavaVM* AndroidRuntimeGetJavaVM(); diff --git a/core/res/res/layout/notification_template_conversation_header.xml b/core/res/res/layout/notification_template_conversation_header.xml index 2faff412565e..eec49fe97b9d 100644 --- a/core/res/res/layout/notification_template_conversation_header.xml +++ b/core/res/res/layout/notification_template_conversation_header.xml @@ -27,7 +27,6 @@ android:id="@+id/conversation_text" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin" android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title" android:textSize="16sp" android:singleLine="true" @@ -40,7 +39,6 @@ android:layout_height="wrap_content" android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info" android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" - android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin" android:text="@string/notification_header_divider_symbol" android:singleLine="true" android:visibility="gone" @@ -53,7 +51,6 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" - android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin" android:singleLine="true" android:visibility="gone" /> @@ -64,7 +61,6 @@ android:layout_height="wrap_content" android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info" android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" - android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin" android:text="@string/notification_header_divider_symbol" android:singleLine="true" android:visibility="gone" @@ -96,7 +92,6 @@ android:layout_height="wrap_content" android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info" android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" - android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin" android:text="@string/notification_header_divider_symbol" android:singleLine="true" android:visibility="gone" @@ -106,7 +101,7 @@ android:id="@+id/verification_icon" android:layout_width="@dimen/notification_verification_icon_size" android:layout_height="@dimen/notification_verification_icon_size" - android:layout_marginStart="4dp" + android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" android:baseline="10dp" android:scaleType="fitCenter" android:src="@drawable/ic_notifications_alerted" @@ -142,7 +137,7 @@ android:id="@+id/phishing_alert" android:layout_width="@dimen/notification_phishing_alert_size" android:layout_height="@dimen/notification_phishing_alert_size" - android:layout_marginStart="4dp" + android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" android:baseline="10dp" android:scaleType="fitCenter" android:src="@drawable/ic_dialog_alert_material" @@ -154,7 +149,7 @@ android:id="@+id/profile_badge" android:layout_width="@dimen/notification_badge_size" android:layout_height="@dimen/notification_badge_size" - android:layout_marginStart="4dp" + android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" android:baseline="10dp" android:scaleType="fitCenter" android:visibility="gone" @@ -165,7 +160,7 @@ android:id="@+id/alerted_icon" android:layout_width="@dimen/notification_alerted_size" android:layout_height="@dimen/notification_alerted_size" - android:layout_marginStart="4dp" + android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" android:baseline="10dp" android:contentDescription="@string/notification_alerted_content_description" android:scaleType="fitCenter" diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index b50ff80ff4e0..9433a7143448 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4408,14 +4408,14 @@ M9,10l-2,0l0,-2l-2,0l0,2l-2,0l0,2l2,0l0,2l2,0l0,-2l2,0z </string> - <!-- X path for SignalDrawable as defined on a 24x24 canvas. --> - <string name="config_signalXPath" translatable="false"> - M22,16.41L20.59,15l-2.09,2.09L16.41,15L15,16.41l2.09,2.09L15,20.59L16.41,22l2.09-2.08L20.59,22L22,20.59l-2.08-2.09 L22,16.41z + <!-- Attribution path for SignalDrawable as defined on a 24x24 canvas. --> + <string name="config_signalAttributionPath" translatable="false"> + M20,10h2v8h-2z M20,20h2v2h-2z </string> <!-- config_signalCutout{Height,Width}Fraction define fraction of the 24x24 canvas that - should be cut out to display config_signalXPath.--> - <item name="config_signalCutoutWidthFraction" format="float" type="dimen">11</item> - <item name="config_signalCutoutHeightFraction" format="float" type="dimen">11</item> + should be cut out to display config_signalAttributionPath. --> + <item name="config_signalCutoutWidthFraction" format="float" type="dimen">7</item> + <item name="config_signalCutoutHeightFraction" format="float" type="dimen">17</item> <!-- A dual tone battery meter draws the perimeter path twice - once to define the shape and a second time clipped to the fill level to indicate charge --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index a940ef3fd7df..70bbc359ba6c 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3370,7 +3370,7 @@ <java-symbol type="string" name="config_batterymeterBoltPath" /> <java-symbol type="string" name="config_batterymeterPowersavePath" /> <java-symbol type="bool" name="config_batterymeterDualTone" /> - <java-symbol type="string" name="config_signalXPath" /> + <java-symbol type="string" name="config_signalAttributionPath" /> <java-symbol type="dimen" name="config_signalCutoutWidthFraction" /> <java-symbol type="dimen" name="config_signalCutoutHeightFraction" /> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java index f3f66dc894ce..28e2f7dd0a63 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java @@ -906,8 +906,7 @@ public class BubbleController { * Fills the overflow bubbles by loading them from disk. */ void loadOverflowBubblesFromDisk() { - if (!mBubbleData.getOverflowBubbles().isEmpty() && !mOverflowDataLoadNeeded) { - // we don't need to load overflow bubbles from disk if it is already in memory + if (!mOverflowDataLoadNeeded) { return; } mOverflowDataLoadNeeded = false; diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp index f70149111116..9e8a1e141fe1 100644 --- a/libs/hwui/renderthread/VulkanManager.cpp +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -579,7 +579,9 @@ void VulkanManager::swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect) std::lock_guard<std::mutex> lock(mGraphicsQueueMutex); mQueueWaitIdle(mGraphicsQueue); } - destroy_semaphore(mDestroySemaphoreContext); + if (mDestroySemaphoreContext) { + destroy_semaphore(mDestroySemaphoreContext); + } surface->presentCurrentBuffer(dirtyRect, fenceFd); mSwapSemaphore = VK_NULL_HANDLE; diff --git a/native/webview/plat_support/draw_functor.cpp b/native/webview/plat_support/draw_functor.cpp index 472e0a4347fc..03dd707a1d09 100644 --- a/native/webview/plat_support/draw_functor.cpp +++ b/native/webview/plat_support/draw_functor.cpp @@ -77,7 +77,18 @@ void draw_gl(int functor, void* data, const uirenderer::DrawGlInfo& draw_gl_params, const uirenderer::WebViewOverlayData& overlay_params) { float gabcdef[7]; - draw_gl_params.color_space_ptr->transferFn(gabcdef); + if (draw_gl_params.color_space_ptr) { + draw_gl_params.color_space_ptr->transferFn(gabcdef); + } else { + // Assume sRGB. + gabcdef[0] = SkNamedTransferFn::kSRGB.g; + gabcdef[1] = SkNamedTransferFn::kSRGB.a; + gabcdef[2] = SkNamedTransferFn::kSRGB.b; + gabcdef[3] = SkNamedTransferFn::kSRGB.c; + gabcdef[4] = SkNamedTransferFn::kSRGB.d; + gabcdef[5] = SkNamedTransferFn::kSRGB.e; + gabcdef[6] = SkNamedTransferFn::kSRGB.f; + } AwDrawFn_DrawGLParams params = { .version = kAwDrawFnVersion, .clip_left = draw_gl_params.clipLeft, @@ -147,7 +158,18 @@ void drawVk(int functor, void* data, const uirenderer::WebViewOverlayData& overlay_params) { SupportData* support = static_cast<SupportData*>(data); float gabcdef[7]; - draw_vk_params.color_space_ptr->transferFn(gabcdef); + if (draw_vk_params.color_space_ptr) { + draw_vk_params.color_space_ptr->transferFn(gabcdef); + } else { + // Assume sRGB. + gabcdef[0] = SkNamedTransferFn::kSRGB.g; + gabcdef[1] = SkNamedTransferFn::kSRGB.a; + gabcdef[2] = SkNamedTransferFn::kSRGB.b; + gabcdef[3] = SkNamedTransferFn::kSRGB.c; + gabcdef[4] = SkNamedTransferFn::kSRGB.d; + gabcdef[5] = SkNamedTransferFn::kSRGB.e; + gabcdef[6] = SkNamedTransferFn::kSRGB.f; + } AwDrawFn_DrawVkParams params{ .version = kAwDrawFnVersion, .width = draw_vk_params.width, diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml index 3814ed5b78fa..f2ab2f852dc6 100644 --- a/packages/SettingsLib/res/values-km/strings.xml +++ b/packages/SettingsLib/res/values-km/strings.xml @@ -452,7 +452,7 @@ <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="7703677921000858479">"ថេប្លេតអាចនឹងបិទក្នុងពេលបន្តិចទៀត (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string> <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="4374784375644214578">"ឧបករណ៍អាចនឹងបិទក្នុងពេលបន្តិចទៀត (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string> <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string> - <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"នៅសល់ <xliff:g id="TIME">%1$s</xliff:g> ទៀតទើបពេញ"</string> + <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> ទៀតទើបពេញ"</string> <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - នៅសល់ <xliff:g id="TIME">%2$s</xliff:g> ទៀតទើបពេញ"</string> <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - បានដាក់កម្រិតការសាកថ្មជាបណ្ដោះអាសន្ន"</string> <string name="battery_info_status_unknown" msgid="268625384868401114">"មិនស្គាល់"</string> diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml index ea6716595d16..864f177fcec9 100644 --- a/packages/SettingsLib/res/values-mr/strings.xml +++ b/packages/SettingsLib/res/values-mr/strings.xml @@ -452,13 +452,13 @@ <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="7703677921000858479">"टॅबलेट लवकरच बंद होऊ शकतो (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string> <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="4374784375644214578">"डिव्हाइस लवकरच बंद होऊ शकते (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string> <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string> - <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"पूर्ण चार्ज होण्यासाठी <xliff:g id="TIME">%1$s</xliff:g> शिल्लक आहे"</string> + <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"पूर्ण चार्ज होण्यासाठी <xliff:g id="TIME">%1$s</xliff:g> शिल्लक आहेत"</string> <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - पूर्ण चार्ज होण्यासाठी <xliff:g id="TIME">%2$s</xliff:g> शिल्लक आहे"</string> <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> • चार्जिंग तात्पुरते मर्यादित आहे"</string> <string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string> <string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज होत आहे"</string> <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"वेगाने चार्ज होत आहे"</string> - <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"हळूहळू चार्ज होत आहे"</string> + <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"हळू चार्ज होत आहे"</string> <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"वायरलेसने चार्ज होत आहे"</string> <string name="battery_info_status_discharging" msgid="6962689305413556485">"चार्ज होत नाही"</string> <string name="battery_info_status_not_charging" msgid="3371084153747234837">"कनेक्ट केले, चार्ज होत नाही"</string> diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml index 0397eb8eaa1a..bb94c2476720 100644 --- a/packages/SettingsLib/res/values-ne/strings.xml +++ b/packages/SettingsLib/res/values-ne/strings.xml @@ -458,7 +458,7 @@ <string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string> <string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज हुँदै छ"</string> <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"द्रुत गतिमा चार्ज गरिँदै छ"</string> - <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"बिस्तारै चार्ज गरिँदै"</string> + <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"ढिलो चार्ज हुँदै छ"</string> <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"वायरलेस तरिकाले चार्ज गरिँदै छ"</string> <string name="battery_info_status_discharging" msgid="6962689305413556485">"चार्ज भइरहेको छैन"</string> <string name="battery_info_status_not_charging" msgid="3371084153747234837">"कनेक्ट गरिएको छ, चार्ज भइरहेको छैन"</string> diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml index aecfd6247b9f..cf6013f969a6 100644 --- a/packages/SettingsLib/res/values-ur/strings.xml +++ b/packages/SettingsLib/res/values-ur/strings.xml @@ -458,7 +458,7 @@ <string name="battery_info_status_unknown" msgid="268625384868401114">"نامعلوم"</string> <string name="battery_info_status_charging" msgid="4279958015430387405">"چارج ہو رہا ہے"</string> <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"تیزی سے چارج ہو رہا ہے"</string> - <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"آہستہ چارج ہو رہا ہے"</string> + <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"آہستہ چارج ہو رہی ہے"</string> <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"وائرلیس طریقے سے چارج ہو رہی ہے"</string> <string name="battery_info_status_discharging" msgid="6962689305413556485">"چارج نہیں ہو رہا ہے"</string> <string name="battery_info_status_not_charging" msgid="3371084153747234837">"منسلک ہے، چارج نہیں ہو رہی ہے"</string> diff --git a/packages/SettingsLib/res/values-zh-rCN/arrays.xml b/packages/SettingsLib/res/values-zh-rCN/arrays.xml index 970efa67e075..400973b4e095 100644 --- a/packages/SettingsLib/res/values-zh-rCN/arrays.xml +++ b/packages/SettingsLib/res/values-zh-rCN/arrays.xml @@ -170,7 +170,7 @@ <item msgid="3691785423374588514">"1M"</item> </string-array> <string-array name="select_logd_size_summaries"> - <item msgid="409235464399258501">"关闭"</item> + <item msgid="409235464399258501">"已关闭"</item> <item msgid="4195153527464162486">"每个日志缓冲区 64K"</item> <item msgid="7464037639415220106">"每个日志缓冲区 256K"</item> <item msgid="8539423820514360724">"每个日志缓冲区 1M"</item> @@ -184,7 +184,7 @@ <item msgid="7300881231043255746">"仅限内核"</item> </string-array> <string-array name="select_logpersist_summaries"> - <item msgid="97587758561106269">"关闭"</item> + <item msgid="97587758561106269">"已关闭"</item> <item msgid="7126170197336963369">"所有日志缓冲区"</item> <item msgid="7167543126036181392">"所有非无线电日志缓冲区"</item> <item msgid="5135340178556563979">"仅限内核日志缓冲区"</item> diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml index ac49b9913c44..e9914510debd 100644 --- a/packages/SettingsLib/res/values-zh-rCN/strings.xml +++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml @@ -276,7 +276,7 @@ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="2040810756832027227">"正在流式传输:<xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string> <string name="select_private_dns_configuration_title" msgid="7887550926056143018">"私人 DNS"</string> <string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"选择私人 DNS 模式"</string> - <string name="private_dns_mode_off" msgid="7065962499349997041">"关闭"</string> + <string name="private_dns_mode_off" msgid="7065962499349997041">"已关闭"</string> <string name="private_dns_mode_opportunistic" msgid="1947864819060442354">"自动"</string> <string name="private_dns_mode_provider" msgid="3619040641762557028">"私人 DNS 提供商主机名"</string> <string name="private_dns_mode_provider_hostname_hint" msgid="6564868953748514595">"输入 DNS 提供商的主机名"</string> diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml index c3caa6d9577c..6d8a0b04bd5c 100644 --- a/packages/SettingsLib/res/values-zh-rHK/strings.xml +++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml @@ -458,7 +458,7 @@ <string name="battery_info_status_unknown" msgid="268625384868401114">"未知"</string> <string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string> <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"快速充電中"</string> - <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"正在慢速充電"</string> + <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"慢速充電中"</string> <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"無線充電中"</string> <string name="battery_info_status_discharging" msgid="6962689305413556485">"非充電中"</string> <string name="battery_info_status_not_charging" msgid="3371084153747234837">"已連接,非充電中"</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java b/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java index 3b41fa99d6c4..4d0804e1bbb7 100644 --- a/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java +++ b/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java @@ -72,9 +72,9 @@ public class SignalDrawable extends DrawableWrapper { private final int mLightModeFillColor; private final Path mCutoutPath = new Path(); private final Path mForegroundPath = new Path(); - private final Path mXPath = new Path(); - private final Matrix mXScaleMatrix = new Matrix(); - private final Path mScaledXPath = new Path(); + private final Path mAttributionPath = new Path(); + private final Matrix mAttributionScaleMatrix = new Matrix(); + private final Path mScaledAttributionPath = new Path(); private final Handler mHandler; private final float mCutoutWidthFraction; private final float mCutoutHeightFraction; @@ -85,10 +85,10 @@ public class SignalDrawable extends DrawableWrapper { public SignalDrawable(Context context) { super(context.getDrawable(com.android.internal.R.drawable.ic_signal_cellular)); - final String xPathString = context.getString( - com.android.internal.R.string.config_signalXPath); - mXPath.set(PathParser.createPathFromPathData(xPathString)); - updateScaledXPath(); + final String attributionPathString = context.getString( + com.android.internal.R.string.config_signalAttributionPath); + mAttributionPath.set(PathParser.createPathFromPathData(attributionPathString)); + updateScaledAttributionPath(); mCutoutWidthFraction = context.getResources().getFloat( com.android.internal.R.dimen.config_signalCutoutWidthFraction); mCutoutHeightFraction = context.getResources().getFloat( @@ -104,13 +104,14 @@ public class SignalDrawable extends DrawableWrapper { setDarkIntensity(0); } - private void updateScaledXPath() { + private void updateScaledAttributionPath() { if (getBounds().isEmpty()) { - mXScaleMatrix.setScale(1f, 1f); + mAttributionScaleMatrix.setScale(1f, 1f); } else { - mXScaleMatrix.setScale(getBounds().width() / VIEWPORT, getBounds().height() / VIEWPORT); + mAttributionScaleMatrix.setScale( + getBounds().width() / VIEWPORT, getBounds().height() / VIEWPORT); } - mXPath.transform(mXScaleMatrix, mScaledXPath); + mAttributionPath.transform(mAttributionScaleMatrix, mScaledAttributionPath); } @Override @@ -177,7 +178,7 @@ public class SignalDrawable extends DrawableWrapper { @Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); - updateScaledXPath(); + updateScaledAttributionPath(); invalidateSelf(); } @@ -221,7 +222,7 @@ public class SignalDrawable extends DrawableWrapper { mCutoutPath.rLineTo(cutX, 0); mCutoutPath.rLineTo(0, cutY); canvas.drawPath(mCutoutPath, mTransparentPaint); - canvas.drawPath(mScaledXPath, mForegroundPaint); + canvas.drawPath(mScaledAttributionPath, mForegroundPaint); } if (isRtl) { canvas.restore(); diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml index 34bf28aa741e..ee0e4b34e9ff 100644 --- a/packages/SystemUI/res/values-land/dimens.xml +++ b/packages/SystemUI/res/values-land/dimens.xml @@ -32,11 +32,11 @@ --> <dimen name="qs_customize_header_min_height">48dp</dimen> + <!-- In landscape the security footer is actually part of the header, + and needs to be as short as the header --> <dimen name="qs_security_footer_single_line_height">@*android:dimen/quick_qs_offset_height</dimen> <dimen name="qs_footer_padding">14dp</dimen> - <dimen name="qs_footers_margin_bottom">0dp</dimen> <dimen name="qs_security_footer_background_inset">12dp</dimen> - <dimen name="qs_security_footer_corner_radius">28dp</dimen> <dimen name="battery_detail_graph_space_top">9dp</dimen> <dimen name="battery_detail_graph_space_bottom">9dp</dimen> diff --git a/packages/SystemUI/res/values-sw600dp-land/config.xml b/packages/SystemUI/res/values-sw600dp-land/config.xml index e2b2e2590b23..369e45cd4494 100644 --- a/packages/SystemUI/res/values-sw600dp-land/config.xml +++ b/packages/SystemUI/res/values-sw600dp-land/config.xml @@ -18,6 +18,10 @@ <!-- Max number of columns for quick controls area --> <integer name="controls_max_columns">2</integer> + <integer name="quick_settings_num_columns">2</integer> + <integer name="quick_qs_panel_max_rows">4</integer> + <integer name="quick_qs_panel_max_tiles">8</integer> + <!-- Whether to use the split 2-column notification shade --> <bool name="config_use_split_notification_shade">true</bool> </resources> diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml index 2f5e8eaa2263..942cb2bcafa0 100644 --- a/packages/SystemUI/res/values-sw600dp/config.xml +++ b/packages/SystemUI/res/values-sw600dp/config.xml @@ -38,4 +38,6 @@ <!-- Max number of columns for quick controls area --> <integer name="controls_max_columns">4</integer> + <!-- How many lines to show in the security footer --> + <integer name="qs_security_footer_maxLines">1</integer> </resources> diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml index da80b85b38bf..527537b6155e 100644 --- a/packages/SystemUI/res/values-sw600dp/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp/dimens.xml @@ -95,4 +95,9 @@ <dimen name="controls_top_margin">24dp</dimen> <dimen name="global_actions_grid_item_layout_height">80dp</dimen> + + <!-- For large screens the security footer appears below the footer, + same as phones in portrait --> + <dimen name="qs_security_footer_single_line_height">48dp</dimen> + <dimen name="qs_security_footer_background_inset">0dp</dimen> </resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index d72286628c37..bf29cf463dbc 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -86,7 +86,10 @@ <bool name="config_navigation_bar_enable_auto_dim_no_visible_wallpaper">true</bool> <!-- The maximum number of tiles in the QuickQSPanel --> - <integer name="quick_qs_panel_max_columns">4</integer> + <integer name="quick_qs_panel_max_tiles">4</integer> + + <!-- The maximum number of rows in the QuickQSPanel --> + <integer name="quick_qs_panel_max_rows">2</integer> <!-- The number of columns in the QuickSettings --> <integer name="quick_settings_num_columns">2</integer> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java index 933a919efaad..92f8454fc93e 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java @@ -27,6 +27,7 @@ import android.text.method.TextKeyListener; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup.MarginLayoutParams; +import android.view.WindowInsets; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; @@ -227,12 +228,16 @@ public class KeyguardPasswordViewController super.onPause(); }); } - mInputMethodManager.hideSoftInputFromWindow(mView.getWindowToken(), 0); + if (mPasswordEntry.isAttachedToWindow()) { + mPasswordEntry.getWindowInsetsController().hide(WindowInsets.Type.ime()); + } } @Override public void onStartingToHide() { - mInputMethodManager.hideSoftInputFromWindow(mView.getWindowToken(), 0); + if (mPasswordEntry.isAttachedToWindow()) { + mPasswordEntry.getWindowInsetsController().hide(WindowInsets.Type.ime()); + } } private void updateSwitchImeButton() { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 672e2e629620..e315e117fbda 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -1428,32 +1428,42 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab final FaceManager.AuthenticationCallback mFaceAuthenticationCallback = new FaceManager.AuthenticationCallback() { - @Override - public void onAuthenticationFailed() { - handleFaceAuthFailed(); - } + @Override + public void onAuthenticationFailed() { + handleFaceAuthFailed(); + if (mKeyguardBypassController != null) { + mKeyguardBypassController.setUserHasDeviceEntryIntent(false); + } + } - @Override - public void onAuthenticationSucceeded(FaceManager.AuthenticationResult result) { - Trace.beginSection("KeyguardUpdateMonitor#onAuthenticationSucceeded"); - handleFaceAuthenticated(result.getUserId(), result.isStrongBiometric()); - Trace.endSection(); - } + @Override + public void onAuthenticationSucceeded(FaceManager.AuthenticationResult result) { + Trace.beginSection("KeyguardUpdateMonitor#onAuthenticationSucceeded"); + handleFaceAuthenticated(result.getUserId(), result.isStrongBiometric()); + Trace.endSection(); - @Override - public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) { - handleFaceHelp(helpMsgId, helpString.toString()); - } + if (mKeyguardBypassController != null) { + mKeyguardBypassController.setUserHasDeviceEntryIntent(false); + } + } - @Override - public void onAuthenticationError(int errMsgId, CharSequence errString) { - handleFaceError(errMsgId, errString.toString()); - } + @Override + public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) { + handleFaceHelp(helpMsgId, helpString.toString()); + } - @Override - public void onAuthenticationAcquired(int acquireInfo) { - handleFaceAcquired(acquireInfo); - } + @Override + public void onAuthenticationError(int errMsgId, CharSequence errString) { + handleFaceError(errMsgId, errString.toString()); + if (mKeyguardBypassController != null) { + mKeyguardBypassController.setUserHasDeviceEntryIntent(false); + } + } + + @Override + public void onAuthenticationAcquired(int acquireInfo) { + handleFaceAcquired(acquireInfo); + } }; private CancellationSignal mFingerprintCancelSignal; diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index 373d4df146d5..5957be3c271b 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -93,6 +93,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme @NonNull private final AnimatedVectorDrawable mFpToUnlockIcon; @NonNull private final AnimatedVectorDrawable mLockToUnlockIcon; @NonNull private final Drawable mLockIcon; + @NonNull private final Drawable mUnlockIcon; @NonNull private final CharSequence mUnlockedLabel; @NonNull private final CharSequence mLockedLabel; @Nullable private final Vibrator mVibrator; @@ -148,6 +149,10 @@ public class LockIconViewController extends ViewController<LockIconView> impleme mVibrator = vibrator; final Context context = view.getContext(); + mUnlockIcon = mView.getContext().getResources().getDrawable( + R.anim.lock_to_unlock, + mView.getContext().getTheme()); + ((AnimatedVectorDrawable) mUnlockIcon).start(); mLockIcon = mView.getContext().getResources().getDrawable( R.anim.lock_to_unlock, mView.getContext().getTheme()); @@ -227,8 +232,9 @@ public class LockIconViewController extends ViewController<LockIconView> impleme return; } - boolean wasShowingFpIcon = mHasUdfps && !mShowUnlockIcon && !mShowLockIcon; + boolean wasShowingFpIcon = mUdfpsEnrolled && !mShowUnlockIcon && !mShowLockIcon; boolean wasShowingLockIcon = mShowLockIcon; + boolean wasShowingUnlockIcon = mShowUnlockIcon; mShowLockIcon = !mCanDismissLockScreen && !mUserUnlockedWithBiometric && isLockScreen() && (!mUdfpsEnrolled || !mRunningFPS); mShowUnlockIcon = mCanDismissLockScreen && isLockScreen(); @@ -239,14 +245,18 @@ public class LockIconViewController extends ViewController<LockIconView> impleme mView.setVisibility(View.VISIBLE); mView.setContentDescription(mLockedLabel); } else if (mShowUnlockIcon) { - if (wasShowingFpIcon) { - mView.setImageDrawable(mFpToUnlockIcon); - mFpToUnlockIcon.forceAnimationOnUI(); - mFpToUnlockIcon.start(); - } else if (wasShowingLockIcon) { - mView.setImageDrawable(mLockToUnlockIcon); - mLockToUnlockIcon.forceAnimationOnUI(); - mLockToUnlockIcon.start(); + if (!wasShowingUnlockIcon) { + if (wasShowingFpIcon) { + mView.setImageDrawable(mFpToUnlockIcon); + mFpToUnlockIcon.forceAnimationOnUI(); + mFpToUnlockIcon.start(); + } else if (wasShowingLockIcon) { + mView.setImageDrawable(mLockToUnlockIcon); + mLockToUnlockIcon.forceAnimationOnUI(); + mLockToUnlockIcon.start(); + } else { + mView.setImageDrawable(mUnlockIcon); + } } mView.setVisibility(View.VISIBLE); mView.setContentDescription(mUnlockedLabel); @@ -300,6 +310,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme mFpToUnlockIcon.setTint(color); mLockToUnlockIcon.setTint(color); mLockIcon.setTint(color); + mUnlockIcon.setTint(color); } private void updateConfiguration() { @@ -427,7 +438,16 @@ public class LockIconViewController extends ViewController<LockIconView> impleme @Override public void onKeyguardShowingChanged() { + // Reset values in case biometrics were removed (ie: pin/pattern/password => swipe). + // If biometrics were removed, local vars mCanDismissLockScreen and + // mUserUnlockedWithBiometric may not be updated. + mCanDismissLockScreen = mKeyguardStateController.canDismissLockScreen(); updateKeyguardShowing(); + if (mIsKeyguardShowing) { + mUserUnlockedWithBiometric = + mKeyguardUpdateMonitor.getUserUnlockedWithBiometric( + KeyguardUpdateMonitor.getCurrentUser()); + } mUdfpsEnrolled = mKeyguardUpdateMonitor.isUdfpsEnrolled(); updateVisibility(); } diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 65c3847be4e3..cf3c31a7a9d1 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -140,6 +140,7 @@ import java.util.function.Consumer; import javax.inject.Inject; import javax.inject.Named; +import javax.inject.Provider; import dagger.Lazy; @@ -199,6 +200,12 @@ public class Dependency { public static final String ALLOW_NOTIFICATION_LONG_PRESS_NAME = "allow_notif_longpress"; /** + * A provider of {@link EdgeBackGestureHandler}. + */ + public static final String EDGE_BACK_GESTURE_HANDLER_PROVIDER_NAME = + "edge_back_gesture_handler_provider"; + + /** * Key for getting a background Looper for background work. */ public static final DependencyKey<Looper> BG_LOOPER = new DependencyKey<>(BG_LOOPER_NAME); @@ -233,6 +240,12 @@ public class Dependency { */ public static final DependencyKey<String> LEAK_REPORT_EMAIL = new DependencyKey<>(LEAK_REPORT_EMAIL_NAME); + /** + * Key for retrieving an Provider<EdgeBackGestureHandler>. + */ + public static final DependencyKey<Provider<EdgeBackGestureHandler>> + EDGE_BACK_GESTURE_HANDLER_PROVIDER = + new DependencyKey<>(EDGE_BACK_GESTURE_HANDLER_PROVIDER_NAME); private final ArrayMap<Object, Object> mDependencies = new ArrayMap<>(); private final ArrayMap<Object, LazyDependencyCreator> mProviders = new ArrayMap<>(); @@ -358,7 +371,7 @@ public class Dependency { @Inject Lazy<TelephonyListenerManager> mTelephonyListenerManager; @Inject Lazy<SystemStatusAnimationScheduler> mSystemStatusAnimationSchedulerLazy; @Inject Lazy<PrivacyDotViewController> mPrivacyDotViewControllerLazy; - @Inject Lazy<EdgeBackGestureHandler> mEdgeBackGestureHandler; + @Inject Provider<EdgeBackGestureHandler> mEdgeBackGestureHandlerProvider; @Inject Lazy<UiEventLogger> mUiEventLogger; @Inject Lazy<InternetDialogFactory> mInternetDialogFactory; @Inject Lazy<FeatureFlags> mFeatureFlagsLazy; @@ -573,8 +586,8 @@ public class Dependency { mProviders.put(SystemStatusAnimationScheduler.class, mSystemStatusAnimationSchedulerLazy::get); mProviders.put(PrivacyDotViewController.class, mPrivacyDotViewControllerLazy::get); - mProviders.put(EdgeBackGestureHandler.class, mEdgeBackGestureHandler::get); mProviders.put(InternetDialogFactory.class, mInternetDialogFactory::get); + mProviders.put(EDGE_BACK_GESTURE_HANDLER_PROVIDER, () -> mEdgeBackGestureHandlerProvider); mProviders.put(UiEventLogger.class, mUiEventLogger::get); mProviders.put(FeatureFlags.class, mFeatureFlagsLazy::get); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index 59d8cd016bb8..aafacd66e278 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -68,6 +68,7 @@ import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.LockscreenShadeTransitionController; +import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -120,6 +121,7 @@ public class UdfpsController implements DozeReceiver { @NonNull private final AccessibilityManager mAccessibilityManager; @NonNull private final LockscreenShadeTransitionController mLockscreenShadeTransitionController; @Nullable private final UdfpsHbmProvider mHbmProvider; + @NonNull private final KeyguardBypassController mKeyguardBypassController; @VisibleForTesting @NonNull final BiometricOrientationEventListener mOrientationListener; // Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple // sensors, this, in addition to a lot of the code here, will be updated. @@ -397,7 +399,10 @@ public class UdfpsController implements DozeReceiver { handled = true; } if ((withinSensorArea || fromUdfpsView) && shouldTryToDismissKeyguard()) { - Log.v(TAG, "onTouch | dismiss keyguard from ACTION_DOWN"); + Log.v(TAG, "onTouch | dismiss keyguard ACTION_DOWN"); + if (!mOnFingerDown) { + playStartHaptic(); + } mKeyguardViewManager.notifyKeyguardAuthenticated(false /* strongAuth */); mAttemptedToDismissKeyguard = true; } @@ -414,6 +419,16 @@ public class UdfpsController implements DozeReceiver { boolean actionMoveWithinSensorArea = isWithinSensorArea(udfpsView, event.getX(idx), event.getY(idx), fromUdfpsView); + if ((fromUdfpsView || actionMoveWithinSensorArea) + && shouldTryToDismissKeyguard()) { + Log.v(TAG, "onTouch | dismiss keyguard ACTION_MOVE"); + if (!mOnFingerDown) { + playStartHaptic(); + } + mKeyguardViewManager.notifyKeyguardAuthenticated(false /* strongAuth */); + mAttemptedToDismissKeyguard = true; + break; + } if (actionMoveWithinSensorArea) { if (mVelocityTracker == null) { // touches could be injected, so the velocity tracker may not have @@ -449,12 +464,6 @@ public class UdfpsController implements DozeReceiver { Log.v(TAG, "onTouch | finger outside"); onFingerUp(); } - if ((fromUdfpsView || actionMoveWithinSensorArea) - && shouldTryToDismissKeyguard()) { - Log.v(TAG, "onTouch | dismiss keyguard from ACTION_MOVE"); - mKeyguardViewManager.notifyKeyguardAuthenticated(false /* strongAuth */); - mAttemptedToDismissKeyguard = true; - } } Trace.endSection(); break; @@ -509,7 +518,8 @@ public class UdfpsController implements DozeReceiver { @Nullable Vibrator vibrator, @NonNull UdfpsHapticsSimulator udfpsHapticsSimulator, @NonNull Optional<UdfpsHbmProvider> hbmProvider, - @NonNull KeyguardStateController keyguardStateController) { + @NonNull KeyguardStateController keyguardStateController, + @NonNull KeyguardBypassController keyguardBypassController) { mContext = context; mExecution = execution; // TODO (b/185124905): inject main handler and vibrator once done prototyping @@ -539,6 +549,7 @@ public class UdfpsController implements DozeReceiver { onOrientationChanged(); return Unit.INSTANCE; }); + mKeyguardBypassController = keyguardBypassController; mSensorProps = findFirstUdfps(); // At least one UDFPS sensor exists @@ -863,12 +874,17 @@ public class UdfpsController implements DozeReceiver { private void onFingerDown(int x, int y, float minor, float major) { mExecution.assertIsMainThread(); + mKeyguardBypassController.setUserHasDeviceEntryIntent(true); if (mView == null) { Log.w(TAG, "Null view in onFingerDown"); return; } if (!mOnFingerDown) { playStartHaptic(); + + if (!mKeyguardUpdateMonitor.isFaceDetectionRunning()) { + mKeyguardUpdateMonitor.requestFaceAuth(/* userInitiatedRequest */ false); + } } mOnFingerDown = true; mFingerprintManager.onPointerDown(mSensorProps.sensorId, x, y, minor, major); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java index 412b77698159..6a918a6c8d39 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java @@ -21,11 +21,8 @@ import android.annotation.Nullable; import android.content.Context; import android.graphics.PointF; import android.hardware.fingerprint.IUdfpsOverlayController; -import android.media.AudioAttributes; import android.os.Build; import android.os.UserHandle; -import android.os.VibrationEffect; -import android.os.Vibrator; import android.provider.Settings; import android.util.Log; import android.util.TypedValue; @@ -50,12 +47,6 @@ public class UdfpsEnrollHelper { // Enroll with two center touches before going to guided enrollment private static final int NUM_CENTER_TOUCHES = 2; - private static final AudioAttributes VIBRATION_SONFICATION_ATTRIBUTES = - new AudioAttributes.Builder() - .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) - .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) - .build(); - interface Listener { void onEnrollmentProgress(int remaining, int totalSteps); void onLastStepAcquired(); @@ -66,9 +57,6 @@ public class UdfpsEnrollHelper { private final int mEnrollReason; private final boolean mAccessibilityEnabled; @NonNull private final List<PointF> mGuidedEnrollmentPoints; - @NonNull private final Vibrator mVibrator; - @NonNull private final VibrationEffect mEffectClick = - VibrationEffect.get(VibrationEffect.EFFECT_CLICK); private int mTotalSteps = -1; private int mRemainingSteps = -1; @@ -82,7 +70,6 @@ public class UdfpsEnrollHelper { public UdfpsEnrollHelper(@NonNull Context context, int reason) { mContext = context; mEnrollReason = reason; - mVibrator = context.getSystemService(Vibrator.class); final AccessibilityManager am = context.getSystemService(AccessibilityManager.class); mAccessibilityEnabled = am.isEnabled(); @@ -141,7 +128,6 @@ public class UdfpsEnrollHelper { if (remaining != mRemainingSteps) { mLocationsEnrolled++; - vibrateSuccess(); } mRemainingSteps = remaining; @@ -202,11 +188,6 @@ public class UdfpsEnrollHelper { if (mRemainingSteps <= 2 && mRemainingSteps >= 0) { mListener.onLastStepAcquired(); - vibrateSuccess(); } } - - private void vibrateSuccess() { - mVibrator.vibrate(mEffectClick, VIBRATION_SONFICATION_ATTRIBUTES); - } } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java index 23c066a75732..0d91f7b3597a 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java @@ -18,6 +18,7 @@ package com.android.systemui.navigationbar; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; +import static com.android.systemui.Dependency.EDGE_BACK_GESTURE_HANDLER_PROVIDER; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; @@ -352,7 +353,7 @@ public class NavigationBarView extends FrameLayout implements mNavColorSampleMargin = getResources() .getDimensionPixelSize(R.dimen.navigation_handle_sample_horizontal_margin); - mEdgeBackGestureHandler = Dependency.get(EdgeBackGestureHandler.class); + mEdgeBackGestureHandler = Dependency.get(EDGE_BACK_GESTURE_HANDLER_PROVIDER).get(); mEdgeBackGestureHandler.setStateChangeCallback(this::updateStates); mRegionSamplingHelper = new RegionSamplingHelper(this, new RegionSamplingHelper.SamplingCallback() { diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java index ff5d0b157c80..48d2bb91da05 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java @@ -58,7 +58,6 @@ import com.android.internal.policy.GestureNavigationSettingsObserver; import com.android.systemui.R; import com.android.systemui.SystemUIFactory; import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.model.SysUiState; import com.android.systemui.navigationbar.NavigationBarView; @@ -92,7 +91,6 @@ import javax.inject.Inject; /** * Utility class to handle edge swipes for back gesture */ -@SysUISingleton public class EdgeBackGestureHandler extends CurrentUserTracker implements PluginListener<NavigationEdgeBackPlugin>, ProtoTraceable<SystemUiTraceProto> { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index 7c7f56658919..f20a2db75f2e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -42,7 +42,6 @@ import com.android.systemui.settings.brightness.BrightnessSlider; import com.android.systemui.statusbar.policy.BrightnessMirrorController; import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; -import com.android.systemui.util.animation.UniqueObjectHostView; import java.util.ArrayList; import java.util.List; @@ -316,7 +315,6 @@ public class QSPanel extends LinearLayout implements Tunable { super.onConfigurationChanged(newConfig); mOnConfigurationChangedListeners.forEach( listener -> listener.onConfigurationChange(newConfig)); - switchSecurityFooter(); } @Override @@ -359,25 +357,21 @@ public class QSPanel extends LinearLayout implements Tunable { switchToParent(mFooter, parent, index); index++; } - - // The security footer is switched on orientation changes } - private void switchSecurityFooter() { - if (mSecurityFooter != null) { - if (mContext.getResources().getConfiguration().orientation - == Configuration.ORIENTATION_LANDSCAPE && mHeaderContainer != null) { - // Adding the security view to the header, that enables us to avoid scrolling - switchToParent(mSecurityFooter, mHeaderContainer, 0); - } else { - // Where should this go? If there's media, right before it. Otherwise, at the end. - View mediaView = findViewByPredicate(v -> v instanceof UniqueObjectHostView); - int index = -1; - if (mediaView != null) { - index = indexOfChild(mediaView); - } - switchToParent(mSecurityFooter, this, index); - } + /** Switch the security footer between top and bottom of QS depending on orientation. */ + public void switchSecurityFooter(boolean shouldUseSplitNotificationShade) { + if (mSecurityFooter == null) return; + + if (!shouldUseSplitNotificationShade + && mContext.getResources().getConfiguration().orientation + == Configuration.ORIENTATION_LANDSCAPE && mHeaderContainer != null) { + // Adding the security view to the header, that enables us to avoid scrolling + switchToParent(mSecurityFooter, mHeaderContainer, 0); + } else { + // Add after the footer + int index = indexOfChild(mFooter); + switchToParent(mSecurityFooter, this, index + 1); } } @@ -652,9 +646,14 @@ public class QSPanel extends LinearLayout implements Tunable { return mListening; } - public void setSecurityFooter(View view) { + /** + * Set the security footer view and switch it into the right place + * @param view the view in question + * @param shouldUseSplitNotificationShade if QS is in split shade mode + */ + public void setSecurityFooter(View view, boolean shouldUseSplitNotificationShade) { mSecurityFooter = view; - switchSecurityFooter(); + switchSecurityFooter(shouldUseSplitNotificationShade); } protected void setPageMargin(int pageMargin) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java index ae0f5104d20f..7cbd45bd2af4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java @@ -77,6 +77,7 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> { refreshAllTiles(); } updateBrightnessMirror(); + mView.switchSecurityFooter(mShouldUseSplitNotificationShade); } }; @@ -141,7 +142,7 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> { refreshAllTiles(); } mView.addOnConfigurationChangedListener(mOnConfigurationChangedListener); - mView.setSecurityFooter(mQsSecurityFooter.getView()); + mView.setSecurityFooter(mQsSecurityFooter.getView(), mShouldUseSplitNotificationShade); switchTileLayout(true); if (mBrightnessMirrorController != null) { mBrightnessMirrorController.addCallback(mBrightnessMirrorListener); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java index 4739a3f4c7d6..64ef5cfdf7e2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java @@ -69,7 +69,7 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr private final DumpManager mDumpManager; private final FeatureFlags mFeatureFlags; protected final ArrayList<TileRecord> mRecords = new ArrayList<>(); - private boolean mShouldUseSplitNotificationShade; + protected boolean mShouldUseSplitNotificationShade; @Nullable private Consumer<Boolean> mMediaVisibilityChangedListener; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java index 4cd4048f7286..e3c241c372a7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java @@ -33,18 +33,16 @@ import com.android.systemui.plugins.qs.QSTile.State; */ public class QuickQSPanel extends QSPanel { - public static final String NUM_QUICK_TILES = "sysui_qqs_count"; private static final String TAG = "QuickQSPanel"; - // A default value so that we never return 0. - public static final int DEFAULT_MAX_TILES = 6; + // A fallback value for max tiles number when setting via Tuner (parseNumTiles) + public static final int TUNER_MAX_TILES_FALLBACK = 6; private boolean mDisabledByPolicy; private int mMaxTiles; public QuickQSPanel(Context context, AttributeSet attrs) { super(context, attrs); - mMaxTiles = Math.min(DEFAULT_MAX_TILES, - getResources().getInteger(R.integer.quick_qs_panel_max_columns)); + mMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_tiles); } @Override @@ -101,7 +99,7 @@ public class QuickQSPanel extends QSPanel { } public void setMaxTiles(int maxTiles) { - mMaxTiles = Math.min(maxTiles, DEFAULT_MAX_TILES); + mMaxTiles = maxTiles; } @Override @@ -117,17 +115,18 @@ public class QuickQSPanel extends QSPanel { } /** - * Parses the String setting into the number of tiles. Defaults to {@code mDefaultMaxTiles} + * Parses the String setting into the number of tiles. Defaults to + * {@link #TUNER_MAX_TILES_FALLBACK} * * @param numTilesValue value of the setting to parse - * @return parsed value of numTilesValue OR {@code mDefaultMaxTiles} on error + * @return parsed value of numTilesValue OR {@link #TUNER_MAX_TILES_FALLBACK} on error */ public static int parseNumTiles(String numTilesValue) { try { return Integer.parseInt(numTilesValue); } catch (NumberFormatException e) { // Couldn't read an int from the new setting value. Use default. - return DEFAULT_MAX_TILES; + return TUNER_MAX_TILES_FALLBACK; } } @@ -187,7 +186,7 @@ public class QuickQSPanel extends QSPanel { public boolean updateResources() { mCellHeightResId = R.dimen.qs_quick_tile_size; boolean b = super.updateResources(); - mMaxAllowedRows = 2; + mMaxAllowedRows = getResources().getInteger(R.integer.quick_qs_panel_max_rows); return b; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java index fee56b984ecc..d75b0fd5983e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java @@ -43,7 +43,7 @@ public class QuickQSPanelController extends QSPanelControllerBase<QuickQSPanel> private final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener = newConfig -> { - int newMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns); + int newMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_tiles); if (newMaxTiles != mView.getNumQuickTiles()) { setMaxTiles(newMaxTiles); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java index 6d5c53609f81..6e201048abdb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -564,8 +564,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp boolean unlockingAllowed = mUpdateMonitor.isUnlockingWithBiometricAllowed(isStrongBiometric); boolean deviceDreaming = mUpdateMonitor.isDreaming(); - boolean bypass = mKeyguardBypassController.getBypassEnabled(); - + boolean bypass = mKeyguardBypassController.getBypassEnabled() + || mKeyguardBypassController.getUserHasDeviceEntryIntent(); if (!mUpdateMonitor.isDeviceInteractive()) { if (!mKeyguardViewController.isShowing()) { return bypass ? MODE_WAKE_AND_UNLOCK : MODE_ONLY_WAKE; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt index 99df3f18729e..6caeba2e5755 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt @@ -44,6 +44,7 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr private var hasFaceFeature: Boolean private var pendingUnlock: PendingUnlock? = null private val listeners = mutableListOf<OnBypassStateChangedListener>() + var userHasDeviceEntryIntent: Boolean = false // ie: attempted udfps auth private val faceAuthEnabledChangedCallback = object : KeyguardStateController.Callback { override fun onFaceAuthEnabledChanged() = notifyListeners() 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 cdb5212b5a47..8d6e1d80e993 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -59,6 +59,7 @@ import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.LockscreenShadeTransitionController; +import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -136,6 +137,8 @@ public class UdfpsControllerTest extends SysuiTestCase { private UdfpsHapticsSimulator mUdfpsHapticsSimulator; @Mock private KeyguardStateController mKeyguardStateController; + @Mock + private KeyguardBypassController mKeyguardBypassController; private FakeExecutor mFgExecutor; @@ -204,7 +207,8 @@ public class UdfpsControllerTest extends SysuiTestCase { mVibrator, mUdfpsHapticsSimulator, Optional.of(mHbmProvider), - mKeyguardStateController); + mKeyguardStateController, + mKeyguardBypassController); verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture()); mOverlayController = mOverlayCaptor.getValue(); verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java index 0eeb955e6b42..d25b3e3279f4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java @@ -16,8 +16,11 @@ package com.android.systemui.navigationbar; +import static com.android.systemui.Dependency.EDGE_BACK_GESTURE_HANDLER_PROVIDER; + import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; import android.graphics.PixelFormat; import android.hardware.display.DisplayManager; @@ -68,7 +71,8 @@ public class NavigationBarButtonTest extends SysuiTestCase { mDependency.injectMockDependency(OverviewProxyService.class); mDependency.injectMockDependency(KeyguardStateController.class); mDependency.injectMockDependency(NavigationBarController.class); - mDependency.injectMockDependency(EdgeBackGestureHandler.class); + mDependency.injectTestDependency(EDGE_BACK_GESTURE_HANDLER_PROVIDER, + () -> mock(EdgeBackGestureHandler.class)); mNavBar = new NavigationBarView(context, null); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java index 92cd244e2e63..df502f959c81 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java @@ -24,6 +24,7 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.HOME_BUTTON_LONG_PRESS_DURATION_MS; +import static com.android.systemui.Dependency.EDGE_BACK_GESTURE_HANDLER_PROVIDER; import static com.android.systemui.navigationbar.NavigationBar.NavBarActionEvent.NAVBAR_ASSIST_LONGPRESS; import static org.junit.Assert.assertEquals; @@ -135,7 +136,8 @@ public class NavigationBarTest extends SysuiTestCase { mDependency.injectMockDependency(StatusBarStateController.class); mDependency.injectMockDependency(NavigationBarController.class); mOverviewProxyService = mDependency.injectMockDependency(OverviewProxyService.class); - mDependency.injectMockDependency(EdgeBackGestureHandler.class); + mDependency.injectTestDependency(EDGE_BACK_GESTURE_HANDLER_PROVIDER, + () -> mock(EdgeBackGestureHandler.class)); TestableLooper.get(this).runWithLooper(() -> { mNavigationBar = createNavBar(mContext); mExternalDisplayNavigationBar = createNavBar(mSysuiTestableContextExternal); diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java index e4d32f4db709..62871dc6101e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java @@ -16,6 +16,8 @@ package com.android.systemui.navigationbar; +import static com.android.systemui.Dependency.EDGE_BACK_GESTURE_HANDLER_PROVIDER; + import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; @@ -58,7 +60,8 @@ public class NavigationBarTransitionsTest extends SysuiTestCase { mDependency.injectMockDependency(StatusBarStateController.class); mDependency.injectMockDependency(KeyguardStateController.class); mDependency.injectMockDependency(NavigationBarController.class); - mDependency.injectMockDependency(EdgeBackGestureHandler.class); + mDependency.injectTestDependency(EDGE_BACK_GESTURE_HANDLER_PROVIDER, + () -> mock(EdgeBackGestureHandler.class)); doReturn(mContext) .when(mDependency.injectMockDependency(NavigationModeController.class)) .getCurrentUserContext(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NavigationBarContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NavigationBarContextTest.java index d56aa777706b..671b1bea849f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NavigationBarContextTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NavigationBarContextTest.java @@ -16,6 +16,8 @@ package com.android.systemui.navigationbar.buttons; +import static com.android.systemui.Dependency.EDGE_BACK_GESTURE_HANDLER_PROVIDER; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -38,6 +40,7 @@ import com.android.systemui.assist.AssistManager; import com.android.systemui.navigationbar.buttons.ContextualButton; import com.android.systemui.navigationbar.buttons.ContextualButtonGroup; import com.android.systemui.navigationbar.buttons.KeyButtonDrawable; +import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler; import org.junit.Before; import org.junit.Ignore; @@ -65,6 +68,8 @@ public class NavigationBarContextTest extends SysuiTestCase { @Before public void setup() { mDependency.injectMockDependency(AssistManager.class); + mDependency.injectTestDependency(EDGE_BACK_GESTURE_HANDLER_PROVIDER, + () -> mock(EdgeBackGestureHandler.class)); mGroup = new ContextualButtonGroup(GROUP_ID); mBtn0 = new ContextualButton(BUTTON_0_ID, mContext, ICON_RES_ID); diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NearestTouchFrameTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NearestTouchFrameTest.java index c8f223bdd72f..2ab2c941e9df 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NearestTouchFrameTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NearestTouchFrameTest.java @@ -16,10 +16,13 @@ package com.android.systemui.navigationbar.buttons; +import static com.android.systemui.Dependency.EDGE_BACK_GESTURE_HANDLER_PROVIDER; + import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -36,6 +39,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.navigationbar.buttons.NearestTouchFrame; +import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler; import org.junit.Before; import org.junit.Test; @@ -52,6 +56,8 @@ public class NearestTouchFrameTest extends SysuiTestCase { @Before public void setup() { + mDependency.injectTestDependency(EDGE_BACK_GESTURE_HANDLER_PROVIDER, + () -> mock(EdgeBackGestureHandler.class)); Configuration c = new Configuration(mContext.getResources().getConfiguration()); c.smallestScreenWidthDp = 500; mNearestTouchFrame = new NearestTouchFrame(mContext, null, c); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java deleted file mode 100644 index 4f8859927d06..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2017 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.qs; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; -import android.testing.TestableLooper.RunWithLooper; -import android.view.ViewGroup; -import android.widget.FrameLayout; - -import androidx.test.filters.SmallTest; - -import com.android.systemui.SysuiTestCase; -import com.android.systemui.plugins.ActivityStarter; -import com.android.systemui.plugins.qs.QSTileView; -import com.android.systemui.qs.logging.QSLogger; -import com.android.systemui.qs.tileimpl.QSTileImpl; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.util.Collections; - -@RunWith(AndroidTestingRunner.class) -@RunWithLooper -@SmallTest -public class QSPanelTest extends SysuiTestCase { - - private TestableLooper mTestableLooper; - private QSPanel mQsPanel; - @Mock - private QSTileHost mHost; - @Mock - private QSTileImpl dndTile; - @Mock - private QSPanelControllerBase.TileRecord mDndTileRecord; - @Mock - private QSLogger mQSLogger; - private ViewGroup mParentView; - @Mock - private QSDetail.Callback mCallback; - @Mock - private QSTileView mQSTileView; - @Mock - private ActivityStarter mActivityStarter; - - @Before - public void setup() throws Exception { - MockitoAnnotations.initMocks(this); - mTestableLooper = TestableLooper.get(this); - -// // Dependencies for QSSecurityFooter -// mDependency.injectTestDependency(ActivityStarter.class, mActivityStarter); -// mDependency.injectMockDependency(SecurityController.class); -// mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper()); -// mContext.addMockSystemService(Context.USER_SERVICE, mock(UserManager.class)); - mDndTileRecord.tile = dndTile; - mDndTileRecord.tileView = mQSTileView; - - mTestableLooper.runWithLooper(() -> { - mQsPanel = new QSPanel(mContext, null); - mQsPanel.initialize(); - mQsPanel.onFinishInflate(); - // Provides a parent with non-zero size for QSPanel - mParentView = new FrameLayout(mContext); - mParentView.addView(mQsPanel); - - when(dndTile.getTileSpec()).thenReturn("dnd"); - when(mHost.getTiles()).thenReturn(Collections.emptyList()); - when(mHost.createTileView(any(), any(), anyBoolean())).thenReturn(mQSTileView); - mQsPanel.addTile(mDndTileRecord); - mQsPanel.setCallback(mCallback); - }); - } - - @Test - public void testOpenDetailsWithExistingTile_NoException() { - mTestableLooper.processAllMessages(); - mQsPanel.openDetails(dndTile); - mTestableLooper.processAllMessages(); - - verify(mCallback).onShowingDetail(any(), anyInt(), anyInt()); - } - - @Test - public void testOpenDetailsWithNullParameter_NoException() { - mTestableLooper.processAllMessages(); - mQsPanel.openDetails(null); - mTestableLooper.processAllMessages(); - - verify(mCallback, never()).onShowingDetail(any(), anyInt(), anyInt()); - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt new file mode 100644 index 000000000000..a83a5e1f5484 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package com.android.systemui.qs + +import android.content.res.Configuration +import android.content.res.Configuration.ORIENTATION_LANDSCAPE +import android.content.res.Configuration.ORIENTATION_PORTRAIT +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import android.testing.TestableLooper.RunWithLooper +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.LinearLayout +import androidx.test.filters.SmallTest +import com.android.systemui.R +import com.android.systemui.SysuiTestCase +import com.android.systemui.plugins.qs.QSTileView +import com.android.systemui.qs.QSPanelControllerBase.TileRecord +import com.android.systemui.qs.logging.QSLogger +import com.android.systemui.qs.tileimpl.QSTileImpl +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyBoolean +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.Mock +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import org.mockito.Mockito.`when` as whenever + +@RunWith(AndroidTestingRunner::class) +@RunWithLooper +@SmallTest +class QSPanelTest : SysuiTestCase() { + private lateinit var mTestableLooper: TestableLooper + private lateinit var mQsPanel: QSPanel + + @Mock + private lateinit var mHost: QSTileHost + + @Mock + private lateinit var dndTile: QSTileImpl<*> + + @Mock + private lateinit var mDndTileRecord: TileRecord + + @Mock + private lateinit var mQSLogger: QSLogger + private lateinit var mParentView: ViewGroup + + @Mock + private lateinit var mCallback: QSDetail.Callback + + @Mock + private lateinit var mQSTileView: QSTileView + + @Before + @Throws(Exception::class) + fun setup() { + MockitoAnnotations.initMocks(this) + mTestableLooper = TestableLooper.get(this) + + mDndTileRecord.tile = dndTile + mDndTileRecord.tileView = mQSTileView + mTestableLooper.runWithLooper { + mQsPanel = QSPanel(mContext, null) + mQsPanel.initialize() + // QSPanel inflates a footer inside of it, mocking it here + mQsPanel.addView(LinearLayout(mContext).apply { id = R.id.qs_footer }) + mQsPanel.onFinishInflate() + mQsPanel.setSecurityFooter(View(mContext), false) + mQsPanel.setHeaderContainer(LinearLayout(mContext)) + // Provides a parent with non-zero size for QSPanel + mParentView = FrameLayout(mContext).apply { + addView(mQsPanel) + } + + whenever(dndTile.tileSpec).thenReturn("dnd") + whenever(mHost.tiles).thenReturn(emptyList()) + whenever(mHost.createTileView(any(), any(), anyBoolean())).thenReturn(mQSTileView) + mQsPanel.addTile(mDndTileRecord) + mQsPanel.setCallback(mCallback) + } + } + + @Test + fun testOpenDetailsWithExistingTile_NoException() { + mTestableLooper.runWithLooper { + mQsPanel.openDetails(dndTile) + } + + verify(mCallback).onShowingDetail(any(), anyInt(), anyInt()) + } + + @Test + fun testOpenDetailsWithNullParameter_NoException() { + mTestableLooper.runWithLooper { + mQsPanel.openDetails(null) + } + + verify(mCallback, never()).onShowingDetail(any(), anyInt(), anyInt()) + } + + @Test + fun testSecurityFooter_appearsOnBottomOnSplitShade() { + mQsPanel.onConfigurationChanged(getNewOrientationConfig(ORIENTATION_LANDSCAPE)) + mQsPanel.switchSecurityFooter(true) + + mTestableLooper.runWithLooper { + mQsPanel.isExpanded = true + } + + assertThat(mQsPanel.indexOfChild(mQsPanel.mSecurityFooter)).isEqualTo(2) + } + + @Test + fun testSecurityFooter_appearsOnBottomIfPortrait() { + mQsPanel.onConfigurationChanged(getNewOrientationConfig(ORIENTATION_PORTRAIT)) + mQsPanel.switchSecurityFooter(false) + + mTestableLooper.runWithLooper { + mQsPanel.isExpanded = true + } + + assertThat(mQsPanel.indexOfChild(mQsPanel.mSecurityFooter)).isEqualTo(2) + } + + @Test + fun testSecurityFooter_appearsOnTopIfSmallScreenAndLandscape() { + mQsPanel.onConfigurationChanged(getNewOrientationConfig(ORIENTATION_LANDSCAPE)) + mQsPanel.switchSecurityFooter(false) + + mTestableLooper.runWithLooper { + mQsPanel.isExpanded = true + } + + // -1 means that it is part of the mHeaderContainer + assertThat(mQsPanel.indexOfChild(mQsPanel.mSecurityFooter)).isEqualTo(-1) + } + + private fun getNewOrientationConfig(@Configuration.Orientation newOrientation: Int) = + context.resources.configuration.apply { orientation = newOrientation } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index d6492c610a4f..a0b93ad25b8b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -24,6 +24,7 @@ import static android.service.notification.NotificationListenerService.REASON_CA import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.wm.shell.bubbles.Bubbles.DISMISS_NOTIF_CANCEL; import static com.google.common.truth.Truth.assertThat; @@ -441,7 +442,7 @@ public class BubblesTest extends SysuiTestCase { mRow.getKey(), Bubbles.DISMISS_USER_GESTURE); mBubbleController.removeBubble( - mRow.getKey(), Bubbles.DISMISS_NOTIF_CANCEL); + mRow.getKey(), DISMISS_NOTIF_CANCEL); verify(mNotificationEntryManager, times(1)).performRemoveNotification( eq(mRow.getSbn()), any(), anyInt()); assertThat(mBubbleData.getOverflowBubbles()).isEmpty(); @@ -1146,6 +1147,28 @@ public class BubblesTest extends SysuiTestCase { // Verify these are in the overflow assertThat(mBubbleData.getOverflowBubbleWithKey(mBubbleEntryUser11.getKey())).isNotNull(); assertThat(mBubbleData.getOverflowBubbleWithKey(mBubbleEntry2User11.getKey())).isNotNull(); + + // Would have loaded bubbles twice because of user switch + verify(mDataRepository, times(2)).loadBubbles(anyInt(), any()); + } + + /** + * Verifies we only load the overflow data once. + */ + @Test + public void testOverflowLoadedOnce() { + mBubbleController.updateBubble(mBubbleEntry); + mBubbleController.updateBubble(mBubbleEntry2); + mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE); + assertThat(mBubbleData.getOverflowBubbles().isEmpty()).isFalse(); + + mBubbleController.updateBubble(mBubbleEntry); + mBubbleController.updateBubble(mBubbleEntry2); + mBubbleController.removeBubble(mBubbleEntry.getKey(), DISMISS_NOTIF_CANCEL); + mBubbleController.removeBubble(mBubbleEntry2.getKey(), DISMISS_NOTIF_CANCEL); + assertThat(mBubbleData.getOverflowBubbles()).isEmpty(); + + verify(mDataRepository, times(1)).loadBubbles(anyInt(), any()); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java index db8a08cdc5e4..b0dd73ada7cf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java @@ -17,6 +17,7 @@ package com.android.systemui.wmshell; import static android.app.Notification.FLAG_BUBBLE; +import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL; import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; @@ -47,6 +48,7 @@ import android.content.pm.LauncherApps; import android.hardware.display.AmbientDisplayConfiguration; import android.os.Handler; import android.os.PowerManager; +import android.os.UserHandle; import android.service.dreams.IDreamManager; import android.service.notification.NotificationListenerService; import android.service.notification.ZenModeConfig; @@ -172,6 +174,10 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { private ExpandableNotificationRow mNonBubbleNotifRow; private BubbleEntry mBubbleEntry; private BubbleEntry mBubbleEntry2; + + private BubbleEntry mBubbleEntryUser11; + private BubbleEntry mBubbleEntry2User11; + @Mock private Bubbles.BubbleExpandListener mBubbleExpandListener; @Mock @@ -241,6 +247,13 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { mBubbleEntry = BubblesManager.notifToBubbleEntry(mRow); mBubbleEntry2 = BubblesManager.notifToBubbleEntry(mRow2); + UserHandle handle = mock(UserHandle.class); + when(handle.getIdentifier()).thenReturn(11); + mBubbleEntryUser11 = BubblesManager.notifToBubbleEntry( + mNotificationTestHelper.createBubble(handle)); + mBubbleEntry2User11 = BubblesManager.notifToBubbleEntry( + mNotificationTestHelper.createBubble(handle)); + mZenModeConfig.suppressedVisualEffects = 0; when(mZenModeController.getConfig()).thenReturn(mZenModeConfig); @@ -908,6 +921,65 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { groupSummary.getEntry().getSbn().getGroupKey())); } + + /** + * Verifies that when the user changes, the bubbles in the overflow list is cleared. Doesn't + * test the loading from the repository which would be a nice thing to add. + */ + @Test + public void testOnUserChanged_overflowState() { + int firstUserId = mBubbleEntry.getStatusBarNotification().getUser().getIdentifier(); + int secondUserId = mBubbleEntryUser11.getStatusBarNotification().getUser().getIdentifier(); + + mBubbleController.updateBubble(mBubbleEntry); + mBubbleController.updateBubble(mBubbleEntry2); + assertTrue(mBubbleController.hasBubbles()); + mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE); + + // Verify these are in the overflow + assertThat(mBubbleData.getOverflowBubbleWithKey(mBubbleEntry.getKey())).isNotNull(); + assertThat(mBubbleData.getOverflowBubbleWithKey(mBubbleEntry2.getKey())).isNotNull(); + + // Switch users + mBubbleController.onUserChanged(secondUserId); + assertThat(mBubbleData.getOverflowBubbles()).isEmpty(); + + // Give this user some bubbles + mBubbleController.updateBubble(mBubbleEntryUser11); + mBubbleController.updateBubble(mBubbleEntry2User11); + assertTrue(mBubbleController.hasBubbles()); + mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE); + + // Verify these are in the overflow + assertThat(mBubbleData.getOverflowBubbleWithKey(mBubbleEntryUser11.getKey())).isNotNull(); + assertThat(mBubbleData.getOverflowBubbleWithKey(mBubbleEntry2User11.getKey())).isNotNull(); + + // Would have loaded bubbles twice because of user switch + verify(mDataRepository, times(2)).loadBubbles(anyInt(), any()); + } + + /** + * Verifies we only load the overflow data once. + */ + @Test + public void testOverflowLoadedOnce() { + when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getKey())) + .thenReturn(mRow); + when(mNotificationEntryManager.getPendingOrActiveNotif(mRow2.getKey())) + .thenReturn(mRow2); + + mEntryListener.onEntryAdded(mRow); + mEntryListener.onEntryAdded(mRow2); + mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE); + assertThat(mBubbleData.getOverflowBubbles()).isNotEmpty(); + + mEntryListener.onEntryRemoved(mRow, REASON_APP_CANCEL); + mEntryListener.onEntryRemoved(mRow2, REASON_APP_CANCEL); + assertThat(mBubbleData.getOverflowBubbles()).isEmpty(); + + verify(mDataRepository, times(1)).loadBubbles(anyInt(), any()); + } + /** * Sets the bubble metadata flags for this entry. These flags are normally set by * NotificationManagerService when the notification is sent, however, these tests do not diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java index f9fd10817627..207a5e3db06e 100644 --- a/services/core/java/com/android/server/VcnManagementService.java +++ b/services/core/java/com/android/server/VcnManagementService.java @@ -24,6 +24,7 @@ import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; +import static android.telephony.SubscriptionManager.isValidSubscriptionId; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; @@ -435,6 +436,15 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } + private boolean isActiveSubGroup( + @NonNull ParcelUuid subGrp, @NonNull TelephonySubscriptionSnapshot snapshot) { + if (subGrp == null || snapshot == null) { + return false; + } + + return Objects.equals(subGrp, snapshot.getActiveDataSubscriptionGroup()); + } + private class VcnSubscriptionTrackerCallback implements TelephonySubscriptionTrackerCallback { /** * Handles subscription group changes, as notified by {@link TelephonySubscriptionTracker} @@ -452,28 +462,49 @@ public class VcnManagementService extends IVcnManagementService.Stub { // Start any VCN instances as necessary for (Entry<ParcelUuid, VcnConfig> entry : mConfigs.entrySet()) { + final ParcelUuid subGrp = entry.getKey(); + + // TODO(b/193687515): Support multiple VCNs active at the same time if (snapshot.packageHasPermissionsForSubscriptionGroup( - entry.getKey(), entry.getValue().getProvisioningPackageName())) { - if (!mVcns.containsKey(entry.getKey())) { - startVcnLocked(entry.getKey(), entry.getValue()); + subGrp, entry.getValue().getProvisioningPackageName()) + && isActiveSubGroup(subGrp, snapshot)) { + if (!mVcns.containsKey(subGrp)) { + startVcnLocked(subGrp, entry.getValue()); } // Cancel any scheduled teardowns for active subscriptions - mHandler.removeCallbacksAndMessages(mVcns.get(entry.getKey())); + mHandler.removeCallbacksAndMessages(mVcns.get(subGrp)); } } // Schedule teardown of any VCN instances that have lost carrier privileges (after a // delay) for (Entry<ParcelUuid, Vcn> entry : mVcns.entrySet()) { - final VcnConfig config = mConfigs.get(entry.getKey()); + final ParcelUuid subGrp = entry.getKey(); + final VcnConfig config = mConfigs.get(subGrp); + + final boolean isActiveSubGrp = isActiveSubGroup(subGrp, snapshot); + final boolean isValidActiveDataSubIdNotInVcnSubGrp = + isValidSubscriptionId(snapshot.getActiveDataSubscriptionId()) + && !isActiveSubGroup(subGrp, snapshot); + // TODO(b/193687515): Support multiple VCNs active at the same time if (config == null || !snapshot.packageHasPermissionsForSubscriptionGroup( - entry.getKey(), config.getProvisioningPackageName())) { - final ParcelUuid uuidToTeardown = entry.getKey(); + subGrp, config.getProvisioningPackageName()) + || !isActiveSubGrp) { + final ParcelUuid uuidToTeardown = subGrp; final Vcn instanceToTeardown = entry.getValue(); + // TODO(b/193687515): Support multiple VCNs active at the same time + // If directly switching to a subscription not in the current group, + // teardown immediately to prevent other subscription's network from being + // outscored by the VCN. Otherwise, teardown after a delay to ensure that + // SIM profile switches do not trigger the VCN to cycle. + final long teardownDelayMs = + isValidActiveDataSubIdNotInVcnSubGrp + ? 0 + : CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS; mHandler.postDelayed(() -> { synchronized (mLock) { // Guard against case where this is run after a old instance was @@ -489,7 +520,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { uuidToTeardown, VCN_STATUS_CODE_INACTIVE); } } - }, instanceToTeardown, CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); + }, instanceToTeardown, teardownDelayMs); } else { // If this VCN's status has not changed, update it with the new snapshot entry.getValue().updateSubscriptionSnapshot(mLastSnapshot); @@ -553,8 +584,13 @@ public class VcnManagementService extends IVcnManagementService.Stub { private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { logDbg("Starting VCN config for subGrp: " + subscriptionGroup); - // TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active - // VCN. + // TODO(b/193687515): Support multiple VCNs active at the same time + if (!mVcns.isEmpty()) { + // Only one VCN supported at a time; teardown all others before starting new one + for (ParcelUuid uuidToTeardown : mVcns.keySet()) { + stopVcnLocked(uuidToTeardown); + } + } final VcnCallbackImpl vcnCallback = new VcnCallbackImpl(subscriptionGroup); @@ -582,7 +618,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { final Vcn vcn = mVcns.get(subscriptionGroup); vcn.updateConfig(config); } else { - startVcnLocked(subscriptionGroup, config); + // TODO(b/193687515): Support multiple VCNs active at the same time + if (isActiveSubGroup(subscriptionGroup, mLastSnapshot)) { + startVcnLocked(subscriptionGroup, config); + } } } @@ -1007,6 +1046,11 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } + @VisibleForTesting(visibility = Visibility.PRIVATE) + void setLastSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) { + mLastSnapshot = Objects.requireNonNull(snapshot); + } + private void logVdbg(String msg) { if (VDBG) { Slog.v(TAG, msg); diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index b5ead200cea5..795d3d6c3461 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -3334,7 +3334,13 @@ public final class ActiveServices { } } - private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) { + /** + * Bump the given service record into executing state. + * @param oomAdjReason The caller requests it to perform the oomAdjUpdate if it's not null. + * @return {@code true} if it performed oomAdjUpdate. + */ + private boolean bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why, + @Nullable String oomAdjReason) { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, ">>> EXECUTING " + why + " of " + r + " in app " + r.app); else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING, ">>> EXECUTING " @@ -3383,9 +3389,19 @@ public final class ActiveServices { } } } + boolean oomAdjusted = false; + if (oomAdjReason != null && r.app != null + && r.app.mState.getCurProcState() > ActivityManager.PROCESS_STATE_SERVICE) { + // Force an immediate oomAdjUpdate, so the client app could be in the correct process + // state before doing any service related transactions + mAm.enqueueOomAdjTargetLocked(r.app); + mAm.updateOomAdjPendingTargetsLocked(oomAdjReason); + oomAdjusted = true; + } r.executeFg |= fg; r.executeNesting++; r.executingStart = now; + return oomAdjusted; } private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i, @@ -3398,8 +3414,8 @@ public final class ActiveServices { + " rebind=" + rebind); if ((!i.requested || rebind) && i.apps.size() > 0) { try { - bumpServiceExecutingLocked(r, execInFg, "bind"); - r.app.mState.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE); + bumpServiceExecutingLocked(r, execInFg, "bind", + OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE); r.app.getThread().scheduleBindService(r, i.intent.getIntent(), rebind, r.app.mState.getReportedProcState()); if (!rebind) { @@ -3867,14 +3883,13 @@ public final class ActiveServices { final ProcessServiceRecord psr = app.mServices; final boolean newService = psr.startService(r); - bumpServiceExecutingLocked(r, execInFg, "create"); + bumpServiceExecutingLocked(r, execInFg, "create", null /* oomAdjReason */); mAm.updateLruProcessLocked(app, false, null); updateServiceForegroundLocked(psr, /* oomAdj= */ false); - if (enqueueOomAdj) { - mAm.enqueueOomAdjTargetLocked(app); - } else { - mAm.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_START_SERVICE); - } + // Force an immediate oomAdjUpdate, so the client app could be in the correct process state + // before doing any service related transactions + mAm.enqueueOomAdjTargetLocked(app); + mAm.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_START_SERVICE); boolean created = false; try { @@ -3895,7 +3910,6 @@ public final class ActiveServices { mAm.mBatteryStatsService.noteServiceStartLaunch(uid, packageName, serviceName); mAm.notifyPackageUse(r.serviceInfo.packageName, PackageManager.NOTIFY_PACKAGE_USE_SERVICE); - app.mState.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE); thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo), app.mState.getReportedProcState()); @@ -3995,11 +4009,7 @@ public final class ActiveServices { mAm.grantImplicitAccess(r.userId, si.intent, si.callingId, UserHandle.getAppId(r.appInfo.uid) ); - bumpServiceExecutingLocked(r, execInFg, "start"); - if (!oomAdjusted) { - oomAdjusted = true; - mAm.updateOomAdjLocked(r.app, OomAdjuster.OOM_ADJ_REASON_START_SERVICE); - } + bumpServiceExecutingLocked(r, execInFg, "start", null /* oomAdjReason */); if (r.fgRequired && !r.fgWaiting) { if (!r.isForeground) { if (DEBUG_BACKGROUND_CHECK) { @@ -4023,6 +4033,10 @@ public final class ActiveServices { args.add(new ServiceStartArgs(si.taskRemoved, si.id, flags, si.intent)); } + if (!oomAdjusted) { + mAm.enqueueOomAdjTargetLocked(r.app); + mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE); + } ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args); slice.setInlineCountLimit(4); Exception caughtException = null; @@ -4117,7 +4131,7 @@ public final class ActiveServices { } } - boolean needOomAdj = false; + boolean oomAdjusted = false; // Tell the service that it has been unbound. if (r.app != null && r.app.getThread() != null) { for (int i = r.bindings.size() - 1; i >= 0; i--) { @@ -4126,8 +4140,8 @@ public final class ActiveServices { + ": hasBound=" + ibr.hasBound); if (ibr.hasBound) { try { - bumpServiceExecutingLocked(r, false, "bring down unbind"); - needOomAdj = true; + oomAdjusted |= bumpServiceExecutingLocked(r, false, "bring down unbind", + OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); ibr.hasBound = false; ibr.requested = false; r.app.getThread().scheduleUnbindService(r, @@ -4135,7 +4149,6 @@ public final class ActiveServices { } catch (Exception e) { Slog.w(TAG, "Exception when unbinding service " + r.shortInstanceName, e); - needOomAdj = false; serviceProcessGoneLocked(r, enqueueOomAdj); break; } @@ -4247,10 +4260,10 @@ public final class ActiveServices { mAm.updateLruProcessLocked(r.app, false, null); updateServiceForegroundLocked(r.app.mServices, false); try { - bumpServiceExecutingLocked(r, false, "destroy"); + oomAdjusted |= bumpServiceExecutingLocked(r, false, "destroy", + oomAdjusted ? null : OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); mDestroyingServices.add(r); r.destroying = true; - needOomAdj = true; r.app.getThread().scheduleStopService(r); } catch (Exception e) { Slog.w(TAG, "Exception when destroying service " @@ -4266,11 +4279,10 @@ public final class ActiveServices { TAG_SERVICE, "Removed service that is not running: " + r); } - if (needOomAdj) { - if (enqueueOomAdj) { - mAm.enqueueOomAdjTargetLocked(r.app); - } else { - mAm.updateOomAdjLocked(r.app, OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); + if (!oomAdjusted) { + mAm.enqueueOomAdjTargetLocked(r.app); + if (!enqueueOomAdj) { + mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); } } if (r.bindings.size() > 0) { @@ -4387,7 +4399,8 @@ public final class ActiveServices { if (s.app != null && s.app.getThread() != null && b.intent.apps.size() == 0 && b.intent.hasBound) { try { - bumpServiceExecutingLocked(s, false, "unbind"); + bumpServiceExecutingLocked(s, false, "unbind", + OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); if (b.client != s.app && (c.flags&Context.BIND_WAIVE_PRIORITY) == 0 && s.app.mState.getSetProcState() <= PROCESS_STATE_HEAVY_WEIGHT) { // If this service's process is not already in the cached list, @@ -4395,11 +4408,6 @@ public final class ActiveServices { // it to go down there and we want it to start out near the top. mAm.updateLruProcessLocked(s.app, false, null); } - if (enqueueOomAdj) { - mAm.enqueueOomAdjTargetLocked(s.app); - } else { - mAm.updateOomAdjLocked(s.app, OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); - } b.intent.hasBound = false; // Assume the client doesn't want to know about a rebind; // we will deal with that later if it asks for one. diff --git a/services/core/java/com/android/server/am/LmkdStatsReporter.java b/services/core/java/com/android/server/am/LmkdStatsReporter.java index c702d780bd6b..a8d058229a4b 100644 --- a/services/core/java/com/android/server/am/LmkdStatsReporter.java +++ b/services/core/java/com/android/server/am/LmkdStatsReporter.java @@ -43,6 +43,7 @@ public final class LmkdStatsReporter { private static final int LOW_MEM_AND_THRASHING = 4; private static final int DIRECT_RECL_AND_THRASHING = 5; private static final int LOW_MEM_AND_SWAP_UTIL = 6; + private static final int LOW_FILECACHE_AFTER_THRASHING = 7; /** * Processes the LMK_KILL_OCCURRED packet data @@ -100,6 +101,8 @@ public final class LmkdStatsReporter { return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__DIRECT_RECL_AND_THRASHING; case LOW_MEM_AND_SWAP_UTIL: return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_MEM_AND_SWAP_UTIL; + case LOW_FILECACHE_AFTER_THRASHING: + return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_FILECACHE_AFTER_THRASHING; default: return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__UNKNOWN; } diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 33bc212fb9c0..24edc01c24df 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -202,6 +202,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.Scanner; import java.util.Set; @@ -775,7 +776,11 @@ public class AppOpsService extends IAppOpsService.Stub { /** Clean up event */ public void finish() { - mClientId.unlinkToDeath(this, 0); + try { + mClientId.unlinkToDeath(this, 0); + } catch (NoSuchElementException e) { + // Either not linked, or already unlinked. Either way, nothing to do. + } } @Override @@ -5099,13 +5104,15 @@ public class AppOpsService extends IAppOpsService.Stub { String lastPkg = null; for (int i=0; i<allOps.size(); i++) { AppOpsManager.PackageOps pkg = allOps.get(i); - if (!pkg.getPackageName().equals(lastPkg)) { + if (!Objects.equals(pkg.getPackageName(), lastPkg)) { if (lastPkg != null) { out.endTag(null, "pkg"); } lastPkg = pkg.getPackageName(); - out.startTag(null, "pkg"); - out.attribute(null, "n", lastPkg); + if (lastPkg != null) { + out.startTag(null, "pkg"); + out.attribute(null, "n", lastPkg); + } } out.startTag(null, "uid"); out.attributeInt(null, "n", pkg.getUid()); diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java index f11fe8aee64f..c2eb06262edd 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java @@ -22,6 +22,7 @@ import android.hardware.biometrics.BiometricConstants; import android.media.AudioAttributes; import android.os.IBinder; import android.os.PowerManager; +import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.VibrationEffect; @@ -49,6 +50,8 @@ public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implement VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK); private final PowerManager mPowerManager; + // If haptics should occur when auth result (success/reject) is known + protected final boolean mShouldVibrate; private boolean mShouldSendErrorToClient = true; private boolean mAlreadyCancelled; @@ -59,11 +62,12 @@ public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implement public AcquisitionClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon, @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId, - @NonNull String owner, int cookie, int sensorId, int statsModality, - int statsAction, int statsClient) { + @NonNull String owner, int cookie, int sensorId, boolean shouldVibrate, + int statsModality, int statsAction, int statsClient) { super(context, lazyDaemon, token, listener, userId, owner, cookie, sensorId, statsModality, statsAction, statsClient); mPowerManager = context.getSystemService(PowerManager.class); + mShouldVibrate = shouldVibrate; } @Override @@ -191,14 +195,22 @@ public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implement protected final void vibrateSuccess() { Vibrator vibrator = getContext().getSystemService(Vibrator.class); if (vibrator != null) { - vibrator.vibrate(SUCCESS_VIBRATION_EFFECT, VIBRATION_SONIFICATION_ATTRIBUTES); + vibrator.vibrate(Process.myUid(), + getContext().getOpPackageName(), + SUCCESS_VIBRATION_EFFECT, + getClass().getSimpleName() + "::success", + VIBRATION_SONIFICATION_ATTRIBUTES); } } protected final void vibrateError() { Vibrator vibrator = getContext().getSystemService(Vibrator.class); if (vibrator != null) { - vibrator.vibrate(ERROR_VIBRATION_EFFECT, VIBRATION_SONIFICATION_ATTRIBUTES); + vibrator.vibrate(Process.myUid(), + getContext().getOpPackageName(), + ERROR_VIBRATION_EFFECT, + getClass().getSimpleName() + "::error", + VIBRATION_SONIFICATION_ATTRIBUTES); } } } diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java index 80e60e67f05a..3e6602e3175a 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java @@ -68,9 +68,11 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> int targetUserId, long operationId, boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation, int sensorId, boolean isStrongBiometric, int statsModality, int statsClient, @Nullable TaskStackListener taskStackListener, - @NonNull LockoutTracker lockoutTracker, boolean allowBackgroundAuthentication) { + @NonNull LockoutTracker lockoutTracker, boolean allowBackgroundAuthentication, + boolean shouldVibrate) { super(context, lazyDaemon, token, listener, targetUserId, owner, cookie, sensorId, - statsModality, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient); + shouldVibrate, statsModality, BiometricsProtoEnums.ACTION_AUTHENTICATE, + statsClient); mIsStrongBiometric = isStrongBiometric; mOperationId = operationId; mRequireConfirmation = requireConfirmation; @@ -204,7 +206,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> mAlreadyDone = true; - if (listener != null) { + if (listener != null && mShouldVibrate) { vibrateSuccess(); } @@ -250,7 +252,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> Slog.w(TAG, "Client not listening"); } } else { - if (listener != null) { + if (listener != null && mShouldVibrate) { vibrateError(); } diff --git a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java index e1320d8e1a4f..a15e14b79e30 100644 --- a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java @@ -38,7 +38,6 @@ public abstract class EnrollClient<T> extends AcquisitionClient<T> { protected final byte[] mHardwareAuthToken; protected final int mTimeoutSec; protected final BiometricUtils mBiometricUtils; - private final boolean mShouldVibrate; private long mEnrollmentStartTimeMs; @@ -50,15 +49,13 @@ public abstract class EnrollClient<T> extends AcquisitionClient<T> { public EnrollClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon, @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull byte[] hardwareAuthToken, @NonNull String owner, @NonNull BiometricUtils utils, - int timeoutSec, int statsModality, int sensorId, - boolean shouldVibrate) { + int timeoutSec, int statsModality, int sensorId, boolean shouldVibrate) { super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId, - statsModality, BiometricsProtoEnums.ACTION_ENROLL, + shouldVibrate, statsModality, BiometricsProtoEnums.ACTION_ENROLL, BiometricsProtoEnums.CLIENT_UNKNOWN); mBiometricUtils = utils; mHardwareAuthToken = Arrays.copyOf(hardwareAuthToken, hardwareAuthToken.length); mTimeoutSec = timeoutSec; - mShouldVibrate = shouldVibrate; } public void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining) { diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java index 3757404d226d..0525d2da6988 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java @@ -73,7 +73,7 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted, owner, cookie, requireConfirmation, sensorId, isStrongBiometric, BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */, - lockoutCache, allowBackgroundAuthentication); + lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */); mUsageStats = usageStats; mLockoutCache = lockoutCache; mNotificationManager = context.getSystemService(NotificationManager.class); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java index cb966e7b47a9..1e73ac528f08 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java @@ -46,8 +46,8 @@ public class FaceDetectClient extends AcquisitionClient<ISession> implements Det @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull String owner, int sensorId, boolean isStrongBiometric, int statsClient) { super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId, - BiometricsProtoEnums.MODALITY_FACE, BiometricsProtoEnums.ACTION_AUTHENTICATE, - statsClient); + true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FACE, + BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient); mIsStrongBiometric = isStrongBiometric; } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java index c3de7aa74d15..5731d73dfd49 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java @@ -65,7 +65,7 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> { super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted, owner, cookie, requireConfirmation, sensorId, isStrongBiometric, BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */, - lockoutTracker, allowBackgroundAuthentication); + lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */); mUsageStats = usageStats; final Resources resources = getContext().getResources(); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java index 19134e46f08f..8681ad75b7c6 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java @@ -26,6 +26,7 @@ import android.hardware.biometrics.BiometricFingerprintConstants.FingerprintAcqu import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.biometrics.common.ICancellationSignal; import android.hardware.biometrics.fingerprint.ISession; +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IUdfpsOverlayController; import android.os.IBinder; import android.os.RemoteException; @@ -62,11 +63,12 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp int sensorId, boolean isStrongBiometric, int statsClient, @Nullable TaskStackListener taskStackListener, @NonNull LockoutCache lockoutCache, @Nullable IUdfpsOverlayController udfpsOverlayController, - boolean allowBackgroundAuthentication) { + boolean allowBackgroundAuthentication, + @NonNull FingerprintSensorPropertiesInternal sensorProps) { super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted, owner, cookie, requireConfirmation, sensorId, isStrongBiometric, BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener, - lockoutCache, allowBackgroundAuthentication); + lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */); mLockoutCache = lockoutCache; mUdfpsOverlayController = udfpsOverlayController; } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java index 5e1a245554a6..c5dc44988612 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java @@ -52,8 +52,8 @@ class FingerprintDetectClient extends AcquisitionClient<ISession> implements Det @Nullable IUdfpsOverlayController udfpsOverlayController, boolean isStrongBiometric, int statsClient) { super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId, - BiometricsProtoEnums.MODALITY_FINGERPRINT, BiometricsProtoEnums.ACTION_AUTHENTICATE, - statsClient); + true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FINGERPRINT, + BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient); mIsStrongBiometric = isStrongBiometric; mUdfpsOverlayController = udfpsOverlayController; } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java index 646b988545be..a211bb5e14e3 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java @@ -65,7 +65,7 @@ class FingerprintEnrollClient extends EnrollClient<ISession> implements Udfps { @Nullable IUdfpsOverlayController udfpsOvelayController, @Nullable ISidefpsController sidefpsController, int maxTemplatesPerUser, @FingerprintManager.EnrollReason int enrollReason) { - // UDFPS enroll vibrations are handled in SystemUI + // UDFPS haptics occur when an image is acquired (instead of when the result is known) super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils, 0 /* timeoutSec */, BiometricsProtoEnums.MODALITY_FINGERPRINT, sensorId, !sensorProps.isAnyUdfpsType() /* shouldVibrate */); @@ -104,6 +104,7 @@ class FingerprintEnrollClient extends EnrollClient<ISession> implements Udfps { // See AcquiredInfo#GOOD and AcquiredInfo#RETRYING_CAPTURE if (acquiredInfo == BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD && mSensorProps.isAnyUdfpsType()) { + vibrateSuccess(); UdfpsHelper.onAcquiredGood(getSensorId(), mUdfpsOverlayController); } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java index 096c3111d35c..cfc467430349 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java @@ -395,7 +395,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi operationId, restricted, opPackageName, cookie, false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient, mTaskStackListener, mSensors.get(sensorId).getLockoutCache(), - mUdfpsOverlayController, allowBackgroundAuthentication); + mUdfpsOverlayController, allowBackgroundAuthentication, + mSensors.get(sensorId).getSensorProperties()); scheduleForSensor(sensorId, client, fingerprintStateCallback); }); } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java index bf7775730a2c..40e3bc3a4698 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java @@ -65,7 +65,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted, owner, cookie, requireConfirmation, sensorId, isStrongBiometric, BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener, - lockoutTracker, allowBackgroundAuthentication); + lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */); mLockoutFrameworkImpl = lockoutTracker; mUdfpsOverlayController = udfpsOverlayController; } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java index 8d777e1c2787..af1e49d250c6 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java @@ -56,8 +56,8 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint> int sensorId, @Nullable IUdfpsOverlayController udfpsOverlayController, boolean isStrongBiometric, int statsClient) { super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId, - BiometricsProtoEnums.MODALITY_FINGERPRINT, BiometricsProtoEnums.ACTION_AUTHENTICATE, - statsClient); + true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FINGERPRINT, + BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient); mUdfpsOverlayController = udfpsOverlayController; mIsStrongBiometric = isStrongBiometric; } diff --git a/services/core/java/com/android/server/location/injector/AlarmHelper.java b/services/core/java/com/android/server/location/injector/AlarmHelper.java index f3fb9c84273b..91a1042d9625 100644 --- a/services/core/java/com/android/server/location/injector/AlarmHelper.java +++ b/services/core/java/com/android/server/location/injector/AlarmHelper.java @@ -33,7 +33,6 @@ public abstract class AlarmHelper { WorkSource workSource) { // helps ensure that we're not wasting system resources by setting alarms in the past/now Preconditions.checkArgument(delayMs > 0); - Preconditions.checkArgument(workSource != null); setDelayedAlarmInternal(delayMs, listener, workSource); } diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java index 8c9068daed9b..8955c288391f 100644 --- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java +++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java @@ -735,8 +735,12 @@ public class LocationProviderManager extends if (mExpirationRealtimeMs <= registerTimeMs) { onAlarm(); } else if (mExpirationRealtimeMs < Long.MAX_VALUE) { + // Set WorkSource to null in order to ensure the alarm wakes up the device even when + // it is idle. Do this when the cost of waking up the device is less than the power + // cost of not performing the actions set off by the alarm, such as unregistering a + // location request. mAlarmHelper.setDelayedAlarm(mExpirationRealtimeMs - registerTimeMs, this, - getRequest().getWorkSource()); + null); } // start listening for provider enabled/disabled events @@ -1122,8 +1126,12 @@ public class LocationProviderManager extends if (mExpirationRealtimeMs <= registerTimeMs) { onAlarm(); } else if (mExpirationRealtimeMs < Long.MAX_VALUE) { + // Set WorkSource to null in order to ensure the alarm wakes up the device even when + // it is idle. Do this when the cost of waking up the device is less than the power + // cost of not performing the actions set off by the alarm, such as unregistering a + // location request. mAlarmHelper.setDelayedAlarm(mExpirationRealtimeMs - registerTimeMs, this, - getRequest().getWorkSource()); + null); } } @@ -1995,7 +2003,11 @@ public class LocationProviderManager extends } } }; - mAlarmHelper.setDelayedAlarm(delayMs, mDelayedRegister, newRequest.getWorkSource()); + // Set WorkSource to null in order to ensure the alarm wakes up the device even when it + // is idle. Do this when the cost of waking up the device is less than the power cost of + // not performing the actions set off by the alarm, such as unregistering a location + // request. + mAlarmHelper.setDelayedAlarm(delayMs, mDelayedRegister, null); } return true; diff --git a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java index f7950aacedc3..f13f4066b94f 100644 --- a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java +++ b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java @@ -141,7 +141,8 @@ final class SpeechRecognitionManagerServiceImpl extends throws RemoteException { attributionSource.enforceCallingUid(); if (!attributionSource.isTrusted(mMaster.getContext())) { - mMaster.getContext().getSystemService(PermissionManager.class) + attributionSource = mMaster.getContext() + .getSystemService(PermissionManager.class) .registerAttributionSource(attributionSource); } service.startListening(recognizerIntent, listener, attributionSource); diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java index fca706b707fa..a31c56a3b737 100644 --- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -36,6 +36,7 @@ import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.util.ArraySet; @@ -85,6 +86,8 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @NonNull private final SubscriptionManager mSubscriptionManager; @NonNull private final CarrierConfigManager mCarrierConfigManager; + @NonNull private final ActiveDataSubscriptionIdListener mActiveDataSubIdListener; + // TODO (Android T+): Add ability to handle multiple subIds per slot. @NonNull private final Map<Integer, Integer> mReadySubIdsBySlotId = new HashMap<>(); @NonNull private final OnSubscriptionsChangedListener mSubscriptionChangedListener; @@ -112,6 +115,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { mTelephonyManager = mContext.getSystemService(TelephonyManager.class); mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); + mActiveDataSubIdListener = new ActiveDataSubscriptionIdListener(); mSubscriptionChangedListener = new OnSubscriptionsChangedListener() { @@ -124,16 +128,20 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { /** Registers the receivers, and starts tracking subscriptions. */ public void register() { + final HandlerExecutor executor = new HandlerExecutor(mHandler); + mContext.registerReceiver( this, new IntentFilter(ACTION_CARRIER_CONFIG_CHANGED), null, mHandler); mSubscriptionManager.addOnSubscriptionsChangedListener( - new HandlerExecutor(mHandler), mSubscriptionChangedListener); + executor, mSubscriptionChangedListener); + mTelephonyManager.registerTelephonyCallback(executor, mActiveDataSubIdListener); } /** Unregisters the receivers, and stops tracking subscriptions. */ public void unregister() { mContext.unregisterReceiver(this); mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionChangedListener); + mTelephonyManager.unregisterTelephonyCallback(mActiveDataSubIdListener); } /** @@ -185,7 +193,8 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { } final TelephonySubscriptionSnapshot newSnapshot = - new TelephonySubscriptionSnapshot(newSubIdToInfoMap, privilegedPackages); + new TelephonySubscriptionSnapshot( + mDeps.getActiveDataSubscriptionId(), newSubIdToInfoMap, privilegedPackages); // If snapshot was meaningfully updated, fire the callback if (!newSnapshot.equals(mCurrentSnapshot)) { @@ -242,16 +251,20 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { /** TelephonySubscriptionSnapshot is a class containing info about active subscriptions */ public static class TelephonySubscriptionSnapshot { + private final int mActiveDataSubId; private final Map<Integer, SubscriptionInfo> mSubIdToInfoMap; private final Map<ParcelUuid, Set<String>> mPrivilegedPackages; public static final TelephonySubscriptionSnapshot EMPTY_SNAPSHOT = - new TelephonySubscriptionSnapshot(Collections.emptyMap(), Collections.emptyMap()); + new TelephonySubscriptionSnapshot( + INVALID_SUBSCRIPTION_ID, Collections.emptyMap(), Collections.emptyMap()); @VisibleForTesting(visibility = Visibility.PRIVATE) TelephonySubscriptionSnapshot( + int activeDataSubId, @NonNull Map<Integer, SubscriptionInfo> subIdToInfoMap, @NonNull Map<ParcelUuid, Set<String>> privilegedPackages) { + mActiveDataSubId = activeDataSubId; Objects.requireNonNull(subIdToInfoMap, "subIdToInfoMap was null"); Objects.requireNonNull(privilegedPackages, "privilegedPackages was null"); @@ -265,6 +278,22 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { mPrivilegedPackages = Collections.unmodifiableMap(unmodifiableInnerSets); } + /** Returns the active subscription ID. May be INVALID_SUBSCRIPTION_ID */ + public int getActiveDataSubscriptionId() { + return mActiveDataSubId; + } + + /** Returns the active subscription group */ + @Nullable + public ParcelUuid getActiveDataSubscriptionGroup() { + final SubscriptionInfo info = mSubIdToInfoMap.get(getActiveDataSubscriptionId()); + if (info == null) { + return null; + } + + return info.getGroupUuid(); + } + /** Returns the active subscription groups */ @NonNull public Set<ParcelUuid> getActiveSubscriptionGroups() { @@ -313,7 +342,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @Override public int hashCode() { - return Objects.hash(mSubIdToInfoMap, mPrivilegedPackages); + return Objects.hash(mActiveDataSubId, mSubIdToInfoMap, mPrivilegedPackages); } @Override @@ -324,7 +353,8 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { final TelephonySubscriptionSnapshot other = (TelephonySubscriptionSnapshot) obj; - return mSubIdToInfoMap.equals(other.mSubIdToInfoMap) + return mActiveDataSubId == other.mActiveDataSubId + && mSubIdToInfoMap.equals(other.mSubIdToInfoMap) && mPrivilegedPackages.equals(other.mPrivilegedPackages); } @@ -333,6 +363,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { pw.println("TelephonySubscriptionSnapshot:"); pw.increaseIndent(); + pw.println("mActiveDataSubId: " + mActiveDataSubId); pw.println("mSubIdToInfoMap: " + mSubIdToInfoMap); pw.println("mPrivilegedPackages: " + mPrivilegedPackages); @@ -342,7 +373,8 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @Override public String toString() { return "TelephonySubscriptionSnapshot{ " - + "mSubIdToInfoMap=" + mSubIdToInfoMap + + "mActiveDataSubId=" + mActiveDataSubId + + ", mSubIdToInfoMap=" + mSubIdToInfoMap + ", mPrivilegedPackages=" + mPrivilegedPackages + " }"; } @@ -362,6 +394,14 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { void onNewSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot); } + private class ActiveDataSubscriptionIdListener extends TelephonyCallback + implements TelephonyCallback.ActiveDataSubscriptionIdListener { + @Override + public void onActiveDataSubscriptionIdChanged(int subId) { + handleSubscriptionsChanged(); + } + } + /** External static dependencies for test injection */ @VisibleForTesting(visibility = Visibility.PRIVATE) public static class Dependencies { @@ -369,5 +409,10 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { public boolean isConfigForIdentifiedCarrier(PersistableBundle bundle) { return CarrierConfigManager.isConfigForIdentifiedCarrier(bundle); } + + /** Gets the active Subscription ID */ + public int getActiveDataSubscriptionId() { + return SubscriptionManager.getActiveDataSubscriptionId(); + } } } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index eba3e8551753..b3aa0577d156 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -731,6 +731,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { WindowOrganizerController mWindowOrganizerController; TaskOrganizerController mTaskOrganizerController; + TaskFragmentOrganizerController mTaskFragmentOrganizerController; @Nullable private BackgroundActivityStartCallback mBackgroundActivityStartCallback; @@ -804,6 +805,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", GL_ES_VERSION_UNDEFINED); mWindowOrganizerController = new WindowOrganizerController(this); mTaskOrganizerController = mWindowOrganizerController.mTaskOrganizerController; + mTaskFragmentOrganizerController = + mWindowOrganizerController.mTaskFragmentOrganizerController; } public void onSystemReady() { @@ -3441,7 +3444,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public IWindowOrganizerController getWindowOrganizerController() { - enforceTaskPermission("getWindowOrganizerController()"); return mWindowOrganizerController; } @@ -5657,7 +5659,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public ActivityTokens getTopActivityForTask(int taskId) { synchronized (mGlobalLock) { - final Task task = mRootWindowContainer.anyTaskForId(taskId); + final Task task = mRootWindowContainer.anyTaskForId(taskId, + MATCH_ATTACHED_TASK_ONLY); if (task == null) { Slog.w(TAG, "getApplicationThreadForTopActivity failed:" + " Requested task not found"); diff --git a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java index 35add129309f..75abd171bb9b 100644 --- a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java +++ b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java @@ -26,6 +26,7 @@ import android.content.pm.ParceledListSlice; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; +import android.util.Slog; import android.view.SurfaceControl; import android.window.DisplayAreaAppearedInfo; import android.window.IDisplayAreaOrganizer; @@ -49,7 +50,8 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl final ActivityTaskManagerService mService; private final WindowManagerGlobalLock mGlobalLock; - private final HashMap<Integer, IDisplayAreaOrganizer> mOrganizersByFeatureIds = new HashMap(); + private final HashMap<Integer, DisplayAreaOrganizerState> mOrganizersByFeatureIds = + new HashMap(); private class DeathRecipient implements IBinder.DeathRecipient { int mFeature; @@ -63,12 +65,41 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl @Override public void binderDied() { synchronized (mGlobalLock) { - mOrganizersByFeatureIds.remove(mFeature); - removeOrganizer(mOrganizer); + mOrganizersByFeatureIds.remove(mFeature).destroy(); } } } + private class DisplayAreaOrganizerState { + private final IDisplayAreaOrganizer mOrganizer; + private final DeathRecipient mDeathRecipient; + + DisplayAreaOrganizerState(IDisplayAreaOrganizer organizer, int feature) { + mOrganizer = organizer; + mDeathRecipient = new DeathRecipient(organizer, feature); + try { + organizer.asBinder().linkToDeath(mDeathRecipient, 0); + } catch (RemoteException e) { + // Oh well... + } + } + + void destroy() { + IBinder organizerBinder = mOrganizer.asBinder(); + mService.mRootWindowContainer.forAllDisplayAreas((da) -> { + if (da.mOrganizer != null && da.mOrganizer.asBinder().equals(organizerBinder)) { + if (da.isTaskDisplayArea() && da.asTaskDisplayArea().mCreatedByOrganizer) { + // Delete the organizer created TDA when unregister. + deleteTaskDisplayArea(da.asTaskDisplayArea()); + } else { + da.setOrganizer(null); + } + } + }); + organizerBinder.unlinkToDeath(mDeathRecipient, 0); + } + } + DisplayAreaOrganizerController(ActivityTaskManagerService atm) { mService = atm; mGlobalLock = atm.mGlobalLock; @@ -80,7 +111,8 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl @Nullable IDisplayAreaOrganizer getOrganizerByFeature(int featureId) { - return mOrganizersByFeatureIds.get(featureId); + final DisplayAreaOrganizerState state = mOrganizersByFeatureIds.get(featureId); + return state != null ? state.mOrganizer : null; } @Override @@ -94,17 +126,18 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register display organizer=%s uid=%d", organizer.asBinder(), uid); if (mOrganizersByFeatureIds.get(feature) != null) { - throw new IllegalStateException( - "Replacing existing organizer currently unsupported"); - } + if (mOrganizersByFeatureIds.get(feature).mOrganizer.asBinder() + .isBinderAlive()) { + throw new IllegalStateException( + "Replacing existing organizer currently unsupported"); + } - final DeathRecipient dr = new DeathRecipient(organizer, feature); - try { - organizer.asBinder().linkToDeath(dr, 0); - } catch (RemoteException e) { - // Oh well... + mOrganizersByFeatureIds.remove(feature).destroy(); + Slog.d(TAG, "Replacing dead organizer for feature=" + feature); } + final DisplayAreaOrganizerState state = new DisplayAreaOrganizerState(organizer, + feature); final List<DisplayAreaAppearedInfo> displayAreaInfos = new ArrayList<>(); mService.mRootWindowContainer.forAllDisplays(dc -> { if (!dc.isTrusted()) { @@ -120,7 +153,7 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl }); }); - mOrganizersByFeatureIds.put(feature, organizer); + mOrganizersByFeatureIds.put(feature, state); return new ParceledListSlice<>(displayAreaInfos); } } finally { @@ -137,9 +170,11 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl synchronized (mGlobalLock) { ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Unregister display organizer=%s uid=%d", organizer.asBinder(), uid); - mOrganizersByFeatureIds.entrySet().removeIf( - entry -> entry.getValue().asBinder() == organizer.asBinder()); - removeOrganizer(organizer); + mOrganizersByFeatureIds.values().forEach((state) -> { + if (state.mOrganizer.asBinder() == organizer.asBinder()) { + state.destroy(); + } + }); } } finally { Binder.restoreCallingIdentity(origId); @@ -190,19 +225,15 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl } final int taskDisplayAreaFeatureId = mNextTaskDisplayAreaFeatureId++; - final DeathRecipient dr = new DeathRecipient(organizer, taskDisplayAreaFeatureId); - try { - organizer.asBinder().linkToDeath(dr, 0); - } catch (RemoteException e) { - // Oh well... - } + final DisplayAreaOrganizerState state = new DisplayAreaOrganizerState(organizer, + taskDisplayAreaFeatureId); final TaskDisplayArea tda = parentRoot != null ? createTaskDisplayArea(parentRoot, name, taskDisplayAreaFeatureId) : createTaskDisplayArea(parentTda, name, taskDisplayAreaFeatureId); final DisplayAreaAppearedInfo tdaInfo = organizeDisplayArea(organizer, tda, "DisplayAreaOrganizerController.createTaskDisplayArea"); - mOrganizersByFeatureIds.put(taskDisplayAreaFeatureId, organizer); + mOrganizersByFeatureIds.put(taskDisplayAreaFeatureId, state); return tdaInfo; } } finally { @@ -230,8 +261,7 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl + "TaskDisplayArea=" + taskDisplayArea); } - mOrganizersByFeatureIds.remove(taskDisplayArea.mFeatureId); - deleteTaskDisplayArea(taskDisplayArea); + mOrganizersByFeatureIds.remove(taskDisplayArea.mFeatureId).destroy(); } } finally { Binder.restoreCallingIdentity(origId); @@ -251,6 +281,10 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl void onDisplayAreaVanished(IDisplayAreaOrganizer organizer, DisplayArea da) { ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "DisplayArea vanished name=%s", da.getName()); + if (!organizer.asBinder().isBinderAlive()) { + Slog.d(TAG, "Organizer died before sending onDisplayAreaVanished"); + return; + } try { organizer.onDisplayAreaVanished(da.getDisplayAreaInfo()); } catch (RemoteException e) { @@ -267,20 +301,6 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl } } - private void removeOrganizer(IDisplayAreaOrganizer organizer) { - IBinder organizerBinder = organizer.asBinder(); - mService.mRootWindowContainer.forAllDisplayAreas((da) -> { - if (da.mOrganizer != null && da.mOrganizer.asBinder().equals(organizerBinder)) { - if (da.isTaskDisplayArea() && da.asTaskDisplayArea().mCreatedByOrganizer) { - // Delete the organizer created TDA when unregister. - deleteTaskDisplayArea(da.asTaskDisplayArea()); - } else { - da.setOrganizer(null); - } - } - }); - } - private DisplayAreaAppearedInfo organizeDisplayArea(IDisplayAreaOrganizer organizer, DisplayArea displayArea, String callsite) { displayArea.setOrganizer(organizer, true /* skipDisplayAreaAppeared */); diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 212f50b762be..7f78bdd2749c 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -1917,7 +1917,7 @@ public class DisplayPolicy { mStatusBarColorWindows.add(win); mStatusBarColorCheckedBounds.union(sTmpRect); } - if (isOverlappingWithNavBar && mNavigationBar == null) { + if (isOverlappingWithNavBar && mNavBarColorWindowCandidate == null) { mNavBarColorWindowCandidate = win; } } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index bd00751c2f41..8235095b9dd5 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -858,6 +858,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // Send any pending task-info changes that were queued-up during a layout deferment mWmService.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); + mWmService.mAtmService.mTaskFragmentOrganizerController.dispatchPendingEvents(); mWmService.mSyncEngine.onSurfacePlacement(); mWmService.mAnimator.executeAfterPrepareSurfacesRunnables(); diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 12ad634fb6b8..59c3ffedb90e 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -82,6 +82,7 @@ import android.util.DisplayMetrics; import android.util.Slog; import android.util.proto.ProtoOutputStream; import android.view.DisplayInfo; +import android.view.SurfaceControl; import android.window.ITaskFragmentOrganizer; import android.window.TaskFragmentInfo; @@ -161,6 +162,11 @@ class TaskFragment extends WindowContainer<WindowContainer> { private TaskFragment mAdjacentTaskFragment; /** + * Prevents duplicate calls to onTaskAppeared. + */ + boolean mTaskFragmentAppearedSent; + + /** * When we are in the process of pausing an activity, before starting the * next one, this variable holds the activity that is currently being paused. * @@ -283,6 +289,12 @@ class TaskFragment extends WindowContainer<WindowContainer> { mTaskFragmentOrganizerPid = pid; } + /** Whether this TaskFragment is organized by the given {@code organizer}. */ + boolean hasTaskFragmentOrganizer(ITaskFragmentOrganizer organizer) { + return organizer != null && mTaskFragmentOrganizer != null + && organizer.asBinder().equals(mTaskFragmentOrganizer.asBinder()); + } + TaskFragment getAdjacentTaskFragment() { return mAdjacentTaskFragment; } @@ -1970,18 +1982,24 @@ class TaskFragment extends WindowContainer<WindowContainer> { @Override public void onConfigurationChanged(Configuration newParentConfig) { super.onConfigurationChanged(newParentConfig); + sendTaskFragmentInfoChanged(); + } + @Override + void setSurfaceControl(SurfaceControl sc) { + super.setSurfaceControl(sc); + // If the TaskFragmentOrganizer was set before we created the SurfaceControl, we need to + // emit the callbacks now. + sendTaskFragmentAppeared(); + } + + void sendTaskFragmentInfoChanged() { if (mTaskFragmentOrganizer != null) { - // Parent config may have changed. The controller will check if there is any important - // config change for the organizer. - mTaskFragmentOrganizerController - .onTaskFragmentParentInfoChanged(mTaskFragmentOrganizer, this); mTaskFragmentOrganizerController .onTaskFragmentInfoChanged(mTaskFragmentOrganizer, this); } } - // TODO(b/190433129) call when TaskFragment is created from WCT#createTaskFragment private void sendTaskFragmentAppeared() { if (mTaskFragmentOrganizer != null) { mTaskFragmentOrganizerController.onTaskFragmentAppeared(mTaskFragmentOrganizer, this); diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java index 56d29dee7b45..496ecdedcaf7 100644 --- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java @@ -19,6 +19,8 @@ package com.android.server.wm; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER; import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer; +import android.annotation.IntDef; +import android.annotation.Nullable; import android.content.res.Configuration; import android.os.Binder; import android.os.IBinder; @@ -33,6 +35,8 @@ import android.window.TaskFragmentInfo; import com.android.internal.protolog.common.ProtoLog; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Map; import java.util.WeakHashMap; @@ -45,16 +49,17 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr private final ActivityTaskManagerService mAtmService; private final WindowManagerGlobalLock mGlobalLock; - private final Map<TaskFragment, TaskFragmentInfo> mLastSentTaskFragmentInfos = - new WeakHashMap<>(); - private final Map<TaskFragment, Configuration> mLastSentTaskFragmentParentConfigs = - new WeakHashMap<>(); /** * A Map which manages the relationship between * {@link ITaskFragmentOrganizer} and {@link TaskFragmentOrganizerState} */ - private final ArrayMap<IBinder, TaskFragmentController> mTaskFragmentOrganizerControllers = + private final ArrayMap<IBinder, TaskFragmentOrganizerState> mTaskFragmentOrganizerState = new ArrayMap<>(); + /** + * A List which manages the TaskFragment pending event {@link PendingTaskFragmentEvent} + */ + private final ArrayList<PendingTaskFragmentEvent> mPendingTaskFragmentEvents = + new ArrayList<>(); TaskFragmentOrganizerController(ActivityTaskManagerService atm) { mAtmService = atm; @@ -65,11 +70,15 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr * A class to manage {@link ITaskFragmentOrganizer} and its organized * {@link TaskFragment TaskFragments}. */ - private class TaskFragmentController implements IBinder.DeathRecipient { + private class TaskFragmentOrganizerState implements IBinder.DeathRecipient { private final ArrayList<TaskFragment> mOrganizedTaskFragments = new ArrayList<>(); private final ITaskFragmentOrganizer mOrganizer; + private final Map<TaskFragment, TaskFragmentInfo> mLastSentTaskFragmentInfos = + new WeakHashMap<>(); + private final Map<TaskFragment, Configuration> mLastSentTaskFragmentParentConfigs = + new WeakHashMap<>(); - TaskFragmentController(ITaskFragmentOrganizer organizer) { + TaskFragmentOrganizerState(ITaskFragmentOrganizer organizer) { mOrganizer = organizer; try { mOrganizer.asBinder().linkToDeath(this, 0 /*flags*/); @@ -85,10 +94,18 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } } - void addTaskFragment(TaskFragment taskFragment) { - if (!mOrganizedTaskFragments.contains(taskFragment)) { - mOrganizedTaskFragments.add(taskFragment); + /** + * @return {@code true} if taskFragment is organized and not sent the appeared event before. + */ + boolean addTaskFragment(TaskFragment taskFragment) { + if (taskFragment.mTaskFragmentAppearedSent) { + return false; + } + if (mOrganizedTaskFragments.contains(taskFragment)) { + return false; } + mOrganizedTaskFragments.add(taskFragment); + return true; } void removeTaskFragment(TaskFragment taskFragment) { @@ -100,6 +117,79 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr mOrganizedTaskFragments.clear(); mOrganizer.asBinder().unlinkToDeath(this, 0 /*flags*/); } + + void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment tf) { + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment appeared name=%s", tf.getName()); + final TaskFragmentInfo info = tf.getTaskFragmentInfo(); + final SurfaceControl outSurfaceControl = new SurfaceControl(tf.getSurfaceControl(), + "TaskFragmentOrganizerController.onTaskFragmentInfoAppeared"); + try { + organizer.onTaskFragmentAppeared( + new TaskFragmentAppearedInfo(info, outSurfaceControl)); + mLastSentTaskFragmentInfos.put(tf, info); + tf.mTaskFragmentAppearedSent = true; + } catch (RemoteException e) { + Slog.e(TAG, "Exception sending onTaskFragmentAppeared callback", e); + } + onTaskFragmentParentInfoChanged(organizer, tf); + } + + void onTaskFragmentVanished(ITaskFragmentOrganizer organizer, TaskFragment tf) { + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment vanished name=%s", tf.getName()); + try { + organizer.onTaskFragmentVanished(tf.getTaskFragmentInfo()); + } catch (RemoteException e) { + Slog.e(TAG, "Exception sending onTaskFragmentVanished callback", e); + } + tf.mTaskFragmentAppearedSent = false; + mLastSentTaskFragmentInfos.remove(tf); + mLastSentTaskFragmentParentConfigs.remove(tf); + } + + void onTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment tf) { + // Parent config may have changed. The controller will check if there is any important + // config change for the organizer. + onTaskFragmentParentInfoChanged(organizer, tf); + + // Check if the info is different from the last reported info. + final TaskFragmentInfo info = tf.getTaskFragmentInfo(); + final TaskFragmentInfo lastInfo = mLastSentTaskFragmentInfos.get(tf); + if (info.equalsForTaskFragmentOrganizer(lastInfo) && configurationsAreEqualForOrganizer( + info.getConfiguration(), lastInfo.getConfiguration())) { + return; + } + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment info changed name=%s", + tf.getName()); + try { + organizer.onTaskFragmentInfoChanged(tf.getTaskFragmentInfo()); + mLastSentTaskFragmentInfos.put(tf, info); + } catch (RemoteException e) { + Slog.e(TAG, "Exception sending onTaskFragmentInfoChanged callback", e); + } + } + + void onTaskFragmentParentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment tf) { + // Check if the parent info is different from the last reported parent info. + if (tf.getParent() == null || tf.getParent().asTask() == null) { + mLastSentTaskFragmentParentConfigs.remove(tf); + return; + } + final Task parent = tf.getParent().asTask(); + final Configuration parentConfig = parent.getConfiguration(); + final Configuration lastParentConfig = mLastSentTaskFragmentParentConfigs.get(tf); + if (configurationsAreEqualForOrganizer(parentConfig, lastParentConfig)) { + return; + } + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, + "TaskFragment parent info changed name=%s parentTaskId=%d", + tf.getName(), parent.mTaskId); + try { + organizer.onTaskFragmentParentInfoChanged(tf.getFragmentToken(), parentConfig); + mLastSentTaskFragmentParentConfigs.put(tf, new Configuration(parentConfig)); + } catch (RemoteException e) { + Slog.e(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e); + } + } } @Override @@ -110,18 +200,18 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register task fragment organizer=%s uid=%d pid=%d", organizer.asBinder(), uid, pid); - if (mTaskFragmentOrganizerControllers.containsKey(organizer.asBinder())) { + if (mTaskFragmentOrganizerState.containsKey(organizer.asBinder())) { throw new IllegalStateException( "Replacing existing organizer currently unsupported"); } - mTaskFragmentOrganizerControllers.put(organizer.asBinder(), - new TaskFragmentController(organizer)); + mTaskFragmentOrganizerState.put(organizer.asBinder(), + new TaskFragmentOrganizerState(organizer)); } } @Override public void unregisterOrganizer(ITaskFragmentOrganizer organizer) { - validateAndGetController(organizer); + validateAndGetState(organizer); final int pid = Binder.getCallingPid(); final long uid = Binder.getCallingUid(); synchronized (mGlobalLock) { @@ -132,88 +222,78 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } } - void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment tf) { - final TaskFragmentController controller = validateAndGetController(organizer); - - ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment appeared name=%s", tf.getName()); - final TaskFragmentInfo info = tf.getTaskFragmentInfo(); - final SurfaceControl outSurfaceControl = new SurfaceControl(tf.getSurfaceControl(), - "TaskFragmentOrganizerController.onTaskFragmentInfoAppeared"); - controller.addTaskFragment(tf); - try { - organizer.onTaskFragmentAppeared( - new TaskFragmentAppearedInfo(info, outSurfaceControl)); - mLastSentTaskFragmentInfos.put(tf, info); - } catch (RemoteException e) { - Slog.e(TAG, "Exception sending onTaskFragmentAppeared callback", e); - } - } - - void onTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment tf) { - validateAndGetController(organizer); - - // Check if the info is different from the last reported info. - final TaskFragmentInfo info = tf.getTaskFragmentInfo(); - final TaskFragmentInfo lastInfo = mLastSentTaskFragmentInfos.get(tf); - if (info.equalsForTaskFragmentOrganizer(lastInfo) && configurationsAreEqualForOrganizer( - info.getConfiguration(), lastInfo.getConfiguration())) { + void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) { + final TaskFragmentOrganizerState state = validateAndGetState(organizer); + if (!state.addTaskFragment(taskFragment)) { return; } - - ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment info changed name=%s", tf.getName()); - try { - organizer.onTaskFragmentInfoChanged(tf.getTaskFragmentInfo()); - mLastSentTaskFragmentInfos.put(tf, info); - } catch (RemoteException e) { - Slog.e(TAG, "Exception sending onTaskFragmentInfoChanged callback", e); + PendingTaskFragmentEvent pendingEvent = getPendingTaskFragmentEvent(taskFragment, + PendingTaskFragmentEvent.EVENT_APPEARED); + if (pendingEvent == null) { + pendingEvent = new PendingTaskFragmentEvent(taskFragment, organizer, + PendingTaskFragmentEvent.EVENT_APPEARED); + mPendingTaskFragmentEvents.add(pendingEvent); } } - void onTaskFragmentVanished(ITaskFragmentOrganizer organizer, TaskFragment tf) { - final TaskFragmentController controller = validateAndGetController(organizer); - - ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment vanished name=%s", tf.getName()); - try { - organizer.onTaskFragmentVanished(tf.getTaskFragmentInfo()); - } catch (RemoteException e) { - Slog.e(TAG, "Exception sending onTaskFragmentVanished callback", e); - } - mLastSentTaskFragmentInfos.remove(tf); - mLastSentTaskFragmentParentConfigs.remove(tf); - controller.removeTaskFragment(tf); + void onTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) { + handleTaskFragmentInfoChanged(organizer, taskFragment, + PendingTaskFragmentEvent.EVENT_INFO_CHANGED); } - void onTaskFragmentParentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment tf) { - validateAndGetController(organizer); + void onTaskFragmentParentInfoChanged(ITaskFragmentOrganizer organizer, + TaskFragment taskFragment) { + handleTaskFragmentInfoChanged(organizer, taskFragment, + PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED); + } - // Check if the parent info is different from the last reported parent info. - if (tf.getParent() == null || tf.getParent().asTask() == null) { - mLastSentTaskFragmentParentConfigs.remove(tf); + private void handleTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer, + TaskFragment taskFragment, int eventType) { + validateAndGetState(organizer); + if (!taskFragment.mTaskFragmentAppearedSent) { + // Skip if TaskFragment still not appeared. return; } - final Task parent = tf.getParent().asTask(); - final Configuration parentConfig = parent.getConfiguration(); - final Configuration lastParentConfig = mLastSentTaskFragmentParentConfigs.get(tf); - if (configurationsAreEqualForOrganizer(parentConfig, lastParentConfig)) { - return; + PendingTaskFragmentEvent pendingEvent = getLastPendingLifecycleEvent(taskFragment); + if (pendingEvent == null) { + pendingEvent = new PendingTaskFragmentEvent(taskFragment, organizer, eventType); + } else { + if (pendingEvent.mEventType == PendingTaskFragmentEvent.EVENT_VANISHED) { + // Skipped the info changed event if vanished event is pending. + return; + } + // Remove and add for re-ordering. + mPendingTaskFragmentEvents.remove(pendingEvent); } + mPendingTaskFragmentEvents.add(pendingEvent); + } - ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, - "TaskFragment parent info changed name=%s parentTaskId=%d", - tf.getName(), parent.mTaskId); - try { - organizer.onTaskFragmentParentInfoChanged(tf.getFragmentToken(), parentConfig); - mLastSentTaskFragmentParentConfigs.put(tf, new Configuration(parentConfig)); - } catch (RemoteException e) { - Slog.e(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e); + void onTaskFragmentVanished(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) { + final TaskFragmentOrganizerState state = validateAndGetState(organizer); + for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) { + PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i); + if (taskFragment == entry.mTaskFragment) { + mPendingTaskFragmentEvents.remove(i); + if (entry.mEventType == PendingTaskFragmentEvent.EVENT_APPEARED) { + // If taskFragment appeared callback is pending, ignore the vanished request. + return; + } + } + } + if (!taskFragment.mTaskFragmentAppearedSent) { + return; } + PendingTaskFragmentEvent pendingEvent = new PendingTaskFragmentEvent(taskFragment, + organizer, PendingTaskFragmentEvent.EVENT_VANISHED); + mPendingTaskFragmentEvents.add(pendingEvent); + state.removeTaskFragment(taskFragment); } private void removeOrganizer(ITaskFragmentOrganizer organizer) { - final TaskFragmentController controller = validateAndGetController(organizer); + final TaskFragmentOrganizerState state = validateAndGetState(organizer); // remove all of the children of the organized TaskFragment - controller.dispose(); - mTaskFragmentOrganizerControllers.remove(organizer.asBinder()); + state.dispose(); + mTaskFragmentOrganizerState.remove(organizer.asBinder()); } /** @@ -222,13 +302,113 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr * we wouldn't register {@link DeathRecipient} for the organizer, and might not remove the * {@link TaskFragment} after the organizer process died. */ - private TaskFragmentController validateAndGetController(ITaskFragmentOrganizer organizer) { - final TaskFragmentController controller = - mTaskFragmentOrganizerControllers.get(organizer.asBinder()); - if (controller == null) { + private TaskFragmentOrganizerState validateAndGetState(ITaskFragmentOrganizer organizer) { + final TaskFragmentOrganizerState state = + mTaskFragmentOrganizerState.get(organizer.asBinder()); + if (state == null) { throw new IllegalArgumentException( "TaskFragmentOrganizer has not been registered. Organizer=" + organizer); } - return controller; + return state; + } + + /** + * A class to store {@link ITaskFragmentOrganizer} and its organized + * {@link TaskFragment TaskFragments} with different pending event request. + */ + private static class PendingTaskFragmentEvent { + static final int EVENT_APPEARED = 0; + static final int EVENT_VANISHED = 1; + static final int EVENT_INFO_CHANGED = 2; + static final int EVENT_PARENT_INFO_CHANGED = 3; + + @IntDef(prefix = "EVENT_", value = { + EVENT_APPEARED, + EVENT_VANISHED, + EVENT_INFO_CHANGED, + EVENT_PARENT_INFO_CHANGED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface EventType {} + + @EventType + final int mEventType; + final TaskFragment mTaskFragment; + final ITaskFragmentOrganizer mTaskFragmentOrg; + + PendingTaskFragmentEvent(TaskFragment taskFragment, ITaskFragmentOrganizer taskFragmentOrg, + @EventType int eventType) { + mTaskFragment = taskFragment; + mTaskFragmentOrg = taskFragmentOrg; + mEventType = eventType; + } + + /** + * @return {@code true} if the pending event is related with taskFragment created, vanished + * and information changed. + */ + boolean isLifecycleEvent() { + switch (mEventType) { + case EVENT_APPEARED: + case EVENT_VANISHED: + case EVENT_INFO_CHANGED: + case EVENT_PARENT_INFO_CHANGED: + return true; + default: + return false; + } + } + } + + @Nullable + private PendingTaskFragmentEvent getLastPendingLifecycleEvent(TaskFragment tf) { + for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) { + PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i); + if (tf == entry.mTaskFragment && entry.isLifecycleEvent()) { + return entry; + } + } + return null; + } + + @Nullable + private PendingTaskFragmentEvent getPendingTaskFragmentEvent(TaskFragment taskFragment, + int type) { + for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) { + PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i); + if (taskFragment == entry.mTaskFragment && type == entry.mEventType) { + return entry; + } + } + return null; + } + + void dispatchPendingEvents() { + if (mAtmService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred() + || mPendingTaskFragmentEvents.isEmpty()) { + return; + } + for (int i = 0, n = mPendingTaskFragmentEvents.size(); i < n; i++) { + PendingTaskFragmentEvent event = mPendingTaskFragmentEvents.get(i); + final ITaskFragmentOrganizer taskFragmentOrg = event.mTaskFragmentOrg; + final TaskFragment taskFragment = event.mTaskFragment; + final TaskFragmentOrganizerState state = + mTaskFragmentOrganizerState.get(taskFragmentOrg.asBinder()); + if (state == null) continue; + switch (event.mEventType) { + case PendingTaskFragmentEvent.EVENT_APPEARED: + state.onTaskFragmentAppeared(taskFragmentOrg, taskFragment); + break; + case PendingTaskFragmentEvent.EVENT_VANISHED: + state.onTaskFragmentVanished(taskFragmentOrg, taskFragment); + break; + case PendingTaskFragmentEvent.EVENT_INFO_CHANGED: + state.onTaskFragmentInfoChanged(taskFragmentOrg, taskFragment); + break; + case PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED: + state.onTaskFragmentParentInfoChanged(taskFragmentOrg, taskFragment); + } + } + mPendingTaskFragmentEvents.clear(); } } diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 4fa3aabaabbc..ffd89d3a94fe 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -54,6 +54,7 @@ import android.util.ArraySet; import android.util.Slog; import android.view.SurfaceControl; import android.window.IDisplayAreaOrganizerController; +import android.window.ITaskFragmentOrganizer; import android.window.ITaskFragmentOrganizerController; import android.window.ITaskOrganizerController; import android.window.ITransitionPlayer; @@ -110,7 +111,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub final TransitionController mTransitionController; /** * A Map which manages the relationship between - * {@link TaskFragmentCreationParams.mFragmentToken fragmentToken} and {@link TaskFragment} + * {@link TaskFragmentCreationParams#getFragmentToken()} and {@link TaskFragment} */ private final ArrayMap<IBinder, TaskFragment> mLaunchTaskFragments = new ArrayMap<>(); @@ -139,10 +140,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub @Override public void applyTransaction(WindowContainerTransaction t) { - enforceTaskPermission("applyTransaction()"); if (t == null) { - throw new IllegalArgumentException("Null transaction passed to applySyncTransaction"); + throw new IllegalArgumentException("Null transaction passed to applyTransaction"); } + enforceTaskPermission("applyTransaction()", t); final CallerInfo caller = new CallerInfo(); final long ident = Binder.clearCallingIdentity(); try { @@ -157,10 +158,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub @Override public int applySyncTransaction(WindowContainerTransaction t, IWindowContainerTransactionCallback callback) { - enforceTaskPermission("applySyncTransaction()"); if (t == null) { throw new IllegalArgumentException("Null transaction passed to applySyncTransaction"); } + enforceTaskPermission("applySyncTransaction()", t); final CallerInfo caller = new CallerInfo(); final long ident = Binder.clearCallingIdentity(); try { @@ -620,7 +621,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub break; case HIERARCHY_OP_TYPE_REPARENT_CHILDREN: final WindowContainer oldParent = WindowContainer.fromBinder(hop.getContainer()); - final WindowContainer newParent = WindowContainer.fromBinder(hop.getNewParent()); + final WindowContainer newParent = hop.getNewParent() != null + ? WindowContainer.fromBinder(hop.getNewParent()) + : null; if (oldParent == null || !oldParent.isAttached()) { Slog.e(TAG, "Attempt to operate on unknown or detached container: " + oldParent); @@ -906,6 +909,102 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub mService.enforceTaskPermission(func); } + private void enforceTaskPermission(String func, WindowContainerTransaction t) { + if (t == null || t.getTaskFragmentOrganizer() == null) { + enforceTaskPermission(func); + return; + } + + // Apps may not have the permission to manage Tasks, but we are allowing apps to manage + // TaskFragments belonging to their own Task. + enforceOperationsAllowedForTaskFragmentOrganizer(func, t); + } + + /** + * Makes sure that the transaction only contains operations that are allowed for the + * {@link WindowContainerTransaction#getTaskFragmentOrganizer()}. + */ + private void enforceOperationsAllowedForTaskFragmentOrganizer( + String func, WindowContainerTransaction t) { + final ITaskFragmentOrganizer organizer = t.getTaskFragmentOrganizer(); + + // Configuration changes + final Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries = + t.getChanges().entrySet().iterator(); + while (entries.hasNext()) { + final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = entries.next(); + // Only allow to apply changes to TaskFragment that is created by this organizer. + enforceTaskFragmentOrganized(func, WindowContainer.fromBinder(entry.getKey()), + organizer); + } + + // Hierarchy changes + final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps(); + for (int i = hops.size() - 1; i >= 0; i--) { + final WindowContainerTransaction.HierarchyOp hop = hops.get(i); + final int type = hop.getType(); + // Check for each type of the operations that are allowed for TaskFragmentOrganizer. + switch (type) { + case HIERARCHY_OP_TYPE_REORDER: + case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT: + enforceTaskFragmentOrganized(func, + WindowContainer.fromBinder(hop.getContainer()), organizer); + break; + case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS: + enforceTaskFragmentOrganized(func, + WindowContainer.fromBinder(hop.getContainer()), organizer); + enforceTaskFragmentOrganized(func, + WindowContainer.fromBinder(hop.getAdjacentRoot()), + organizer); + break; + case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT: + // We are allowing organizer to create TaskFragment. We will check the + // ownerToken in #createTaskFragment, and trigger error callback if that is not + // valid. + case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT: + case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: + // We are allowing organizer to start/reparent activity to a TaskFragment it + // created. Nothing to check here because the TaskFragment may not be created + // yet, but will be created in the same transaction. + break; + case HIERARCHY_OP_TYPE_REPARENT_CHILDREN: + enforceTaskFragmentOrganized(func, + WindowContainer.fromBinder(hop.getContainer()), organizer); + if (hop.getNewParent() != null) { + enforceTaskFragmentOrganized(func, + WindowContainer.fromBinder(hop.getNewParent()), + organizer); + } + break; + default: + // Other types of hierarchy changes are not allowed. + String msg = "Permission Denial: " + func + " from pid=" + + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() + + " trying to apply a hierarchy change that is not allowed for" + + " TaskFragmentOrganizer=" + organizer; + Slog.w(TAG, msg); + throw new SecurityException(msg); + } + } + } + + private void enforceTaskFragmentOrganized(String func, @Nullable WindowContainer wc, + ITaskFragmentOrganizer organizer) { + if (wc == null) { + Slog.e(TAG, "Attempt to operate on window that no longer exists"); + return; + } + + final TaskFragment tf = wc.asTaskFragment(); + if (tf == null || !tf.hasTaskFragmentOrganizer(organizer)) { + String msg = "Permission Denial: " + func + " from pid=" + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid() + " trying to modify window container not" + + " belonging to the TaskFragmentOrganizer=" + organizer; + Slog.w(TAG, msg); + throw new SecurityException(msg); + } + } + void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams) { final ActivityRecord ownerActivity = ActivityRecord.forTokenLocked(creationParams.getOwnerToken()); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java index 46f96364ff9e..a06a78288535 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java @@ -90,7 +90,8 @@ public class AcquisitionClientTest { @NonNull LazyDaemon<Object> lazyDaemon, @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter callback) { super(context, lazyDaemon, token, callback, 0 /* userId */, "Test", 0 /* cookie */, - TEST_SENSOR_ID /* sensorId */, 0 /* statsModality */, 0 /* statsAction */, + TEST_SENSOR_ID /* sensorId */, true /* shouldVibrate */, 0 /* statsModality */, + 0 /* statsAction */, 0 /* statsClient */); } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java index 4d1f241787a7..109fb22520c8 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java @@ -359,7 +359,7 @@ public class BiometricSchedulerTest { false /* restricted */, TAG, 1 /* cookie */, false /* requireConfirmation */, TEST_SENSOR_ID, true /* isStrongBiometric */, 0 /* statsModality */, 0 /* statsClient */, null /* taskStackListener */, mock(LockoutTracker.class), - false /* isKeyguard */); + false /* isKeyguard */, true /* shouldVibrate */); } @Override @@ -382,7 +382,7 @@ public class BiometricSchedulerTest { false /* restricted */, TAG, 1 /* cookie */, false /* requireConfirmation */, TEST_SENSOR_ID, true /* isStrongBiometric */, 0 /* statsModality */, 0 /* statsClient */, null /* taskStackListener */, mock(LockoutTracker.class), - false /* isKeyguard */); + false /* isKeyguard */, true /* shouldVibrate */); } @Override diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java index 9f0cdd56ed7f..225f5b306359 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java @@ -31,6 +31,8 @@ import androidx.test.filters.SmallTest; import com.android.server.hdmi.HdmiUtils.CodecSad; import com.android.server.hdmi.HdmiUtils.DeviceConfig; +import com.google.common.testing.EqualsTester; + import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -116,6 +118,22 @@ public class HdmiUtilsTest { } @Test + public void testEqualsCodecSad() { + byte[] sad = {0x0a, 0x1b, 0x2c}; + String sadString = "0a1b2c"; + new EqualsTester() + .addEqualityGroup( + new HdmiUtils.CodecSad(Constants.AUDIO_CODEC_LPCM, sad), + new HdmiUtils.CodecSad(Constants.AUDIO_CODEC_LPCM, sadString)) + .addEqualityGroup( + new HdmiUtils.CodecSad(Constants.AUDIO_CODEC_LPCM, sadString + "01")) + .addEqualityGroup(new HdmiUtils.CodecSad(Constants.AUDIO_CODEC_DD, sadString)) + .addEqualityGroup( + new HdmiUtils.CodecSad(Constants.AUDIO_CODEC_DD, sadString + "01")) + .testEquals(); + } + + @Test public void parseSampleXML() { List<DeviceConfig> config = new ArrayList<>(); try { diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java index c4faaa31e5a0..9d351f835b19 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java @@ -57,6 +57,7 @@ import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Binder; +import android.os.IBinder; import android.platform.test.annotations.Presubmit; import android.view.SurfaceControl; import android.view.View; @@ -556,6 +557,7 @@ public class DisplayAreaTest extends WindowTestsBase { final DisplayArea<WindowContainer> displayArea = new DisplayArea<>( mWm, BELOW_TASKS, "NewArea", FEATURE_VENDOR_FIRST); final IDisplayAreaOrganizer mockDisplayAreaOrganizer = mock(IDisplayAreaOrganizer.class); + doReturn(mock(IBinder.class)).when(mockDisplayAreaOrganizer).asBinder(); displayArea.mOrganizer = mockDisplayAreaOrganizer; spyOn(mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController); mDisplayContent.addChild(displayArea, 0); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java index 6bd8ad27342a..ac981cf6c7cf 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java @@ -22,6 +22,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.testing.Assert.assertThrows; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; @@ -29,7 +31,9 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import android.content.Intent; import android.content.res.Configuration; +import android.graphics.Rect; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; @@ -37,8 +41,12 @@ import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.view.SurfaceControl; import android.window.ITaskFragmentOrganizer; +import android.window.TaskFragmentCreationParams; import android.window.TaskFragmentInfo; import android.window.TaskFragmentOrganizer; +import android.window.WindowContainerToken; +import android.window.WindowContainerTransaction; +import android.window.WindowContainerTransactionCallback; import androidx.test.filters.SmallTest; @@ -61,18 +69,24 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { private TaskFragment mTaskFragment; private TaskFragmentInfo mTaskFragmentInfo; private IBinder mFragmentToken; + private WindowContainerTransaction mTransaction; + private WindowContainerToken mFragmentWindowToken; @Before public void setup() { mController = mWm.mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController; mOrganizer = new TaskFragmentOrganizer(Runnable::run); mIOrganizer = mOrganizer.getIOrganizer(); - mTaskFragment = mock(TaskFragment.class); mTaskFragmentInfo = mock(TaskFragmentInfo.class); mFragmentToken = new Binder(); + mTaskFragment = + new TaskFragment(mAtm, mFragmentToken, true /* createdByOrganizer */); + mTransaction = new WindowContainerTransaction(); + mFragmentWindowToken = mTaskFragment.mRemoteToken.toWindowContainerToken(); spyOn(mController); spyOn(mOrganizer); + spyOn(mTaskFragment); doReturn(mIOrganizer).when(mTaskFragment).getTaskFragmentOrganizer(); doReturn(mTaskFragmentInfo).when(mTaskFragment).getTaskFragmentInfo(); doReturn(new SurfaceControl()).when(mTaskFragment).getSurfaceControl(); @@ -102,6 +116,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.registerOrganizer(mIOrganizer); mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); + mController.dispatchPendingEvents(); verify(mOrganizer).onTaskFragmentAppeared(any()); } @@ -110,6 +125,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { public void testOnTaskFragmentInfoChanged() { mController.registerOrganizer(mIOrganizer); mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); + mController.dispatchPendingEvents(); // No callback if the info is not changed. doReturn(true).when(mTaskFragmentInfo).equalsForTaskFragmentOrganizer(any()); @@ -117,6 +133,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.onTaskFragmentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); + mController.dispatchPendingEvents(); verify(mOrganizer, never()).onTaskFragmentInfoChanged(any()); @@ -125,6 +142,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.onTaskFragmentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); + mController.dispatchPendingEvents(); verify(mOrganizer).onTaskFragmentInfoChanged(mTaskFragmentInfo); } @@ -133,7 +151,9 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { public void testOnTaskFragmentVanished() { mController.registerOrganizer(mIOrganizer); + mTaskFragment.mTaskFragmentAppearedSent = true; mController.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); + mController.dispatchPendingEvents(); verify(mOrganizer).onTaskFragmentVanished(any()); } @@ -148,8 +168,10 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { doReturn(parentConfig).when(parent).getConfiguration(); doReturn(parent).when(parent).asTask(); + mTaskFragment.mTaskFragmentAppearedSent = true; mController.onTaskFragmentParentInfoChanged( mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); + mController.dispatchPendingEvents(); verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any()); @@ -158,6 +180,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.onTaskFragmentParentInfoChanged( mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); + mController.dispatchPendingEvents(); verify(mOrganizer, never()).onTaskFragmentParentInfoChanged(any(), any()); @@ -166,6 +189,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.onTaskFragmentParentInfoChanged( mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); + mController.dispatchPendingEvents(); verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any()); } @@ -180,4 +204,156 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { verify(mOrganizer).onTaskFragmentError(eq(errorCallbackToken), eq(exception)); } + + @Test + public void testWindowContainerTransaction_setTaskFragmentOrganizer() { + mOrganizer.applyTransaction(mTransaction); + + assertEquals(mIOrganizer, mTransaction.getTaskFragmentOrganizer()); + + mTransaction = new WindowContainerTransaction(); + mOrganizer.applySyncTransaction( + mTransaction, mock(WindowContainerTransactionCallback.class)); + + assertEquals(mIOrganizer, mTransaction.getTaskFragmentOrganizer()); + } + + @Test + public void testApplyTransaction_enforceConfigurationChangeOnOrganizedTaskFragment() + throws RemoteException { + mOrganizer.applyTransaction(mTransaction); + + // Throw exception if the transaction is trying to change a window that is not organized by + // the organizer. + mTransaction.setBounds(mFragmentWindowToken, new Rect(0, 0, 100, 100)); + + assertThrows(SecurityException.class, () -> { + try { + mAtm.getWindowOrganizerController().applyTransaction(mTransaction); + } catch (RemoteException e) { + fail(); + } + }); + + // Allow transaction to change a TaskFragment created by the organizer. + mTaskFragment.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */); + + mAtm.getWindowOrganizerController().applyTransaction(mTransaction); + } + + @Test + public void testApplyTransaction_enforceHierarchyChange_reorder() throws RemoteException { + mOrganizer.applyTransaction(mTransaction); + + // Throw exception if the transaction is trying to change a window that is not organized by + // the organizer. + mTransaction.reorder(mFragmentWindowToken, true /* onTop */); + + assertThrows(SecurityException.class, () -> { + try { + mAtm.getWindowOrganizerController().applyTransaction(mTransaction); + } catch (RemoteException e) { + fail(); + } + }); + + // Allow transaction to change a TaskFragment created by the organizer. + mTaskFragment.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */); + + mAtm.getWindowOrganizerController().applyTransaction(mTransaction); + } + + @Test + public void testApplyTransaction_enforceHierarchyChange_deleteTaskFragment() + throws RemoteException { + mOrganizer.applyTransaction(mTransaction); + + // Throw exception if the transaction is trying to change a window that is not organized by + // the organizer. + mTransaction.deleteTaskFragment(mFragmentWindowToken); + + assertThrows(SecurityException.class, () -> { + try { + mAtm.getWindowOrganizerController().applyTransaction(mTransaction); + } catch (RemoteException e) { + fail(); + } + }); + + // Allow transaction to change a TaskFragment created by the organizer. + mTaskFragment.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */); + + mAtm.getWindowOrganizerController().applyTransaction(mTransaction); + } + + @Test + public void testApplyTransaction_enforceHierarchyChange_setAdjacentRoots() + throws RemoteException { + final TaskFragment taskFragment2 = + new TaskFragment(mAtm, new Binder(), true /* createdByOrganizer */); + final WindowContainerToken token2 = taskFragment2.mRemoteToken.toWindowContainerToken(); + mOrganizer.applyTransaction(mTransaction); + + // Throw exception if the transaction is trying to change a window that is not organized by + // the organizer. + mTransaction.setAdjacentRoots(mFragmentWindowToken, token2); + + assertThrows(SecurityException.class, () -> { + try { + mAtm.getWindowOrganizerController().applyTransaction(mTransaction); + } catch (RemoteException e) { + fail(); + } + }); + + // Allow transaction to change a TaskFragment created by the organizer. + mTaskFragment.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */); + taskFragment2.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */); + + mAtm.getWindowOrganizerController().applyTransaction(mTransaction); + } + + @Test + public void testApplyTransaction_enforceHierarchyChange_createTaskFragment() { + mOrganizer.applyTransaction(mTransaction); + + // Allow organizer to create TaskFragment and start/reparent activity to TaskFragment. + mTransaction.createTaskFragment(mock(TaskFragmentCreationParams.class)); + mTransaction.startActivityInTaskFragment( + mFragmentToken, new Intent(), null /* activityOptions */); + mTransaction.reparentActivityToTaskFragment(mFragmentToken, mock(IBinder.class)); + + // It is expected to fail for the mock TaskFragmentCreationParams. It is ok as we are + // testing the security check here. + assertThrows(IllegalArgumentException.class, () -> { + try { + mAtm.getWindowOrganizerController().applyTransaction(mTransaction); + } catch (RemoteException e) { + fail(); + } + }); + } + + @Test + public void testApplyTransaction_enforceHierarchyChange_reparentChildren() + throws RemoteException { + mOrganizer.applyTransaction(mTransaction); + + // Throw exception if the transaction is trying to change a window that is not organized by + // the organizer. + mTransaction.reparentChildren(mFragmentWindowToken, null /* newParent */); + + assertThrows(SecurityException.class, () -> { + try { + mAtm.getWindowOrganizerController().applyTransaction(mTransaction); + } catch (RemoteException e) { + fail(); + } + }); + + // Allow transaction to change a TaskFragment created by the organizer. + mTaskFragment.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */); + + mAtm.getWindowOrganizerController().applyTransaction(mTransaction); + } } diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java index a427ed612b31..02bd0010de99 100644 --- a/telecomm/java/android/telecom/Phone.java +++ b/telecomm/java/android/telecom/Phone.java @@ -139,6 +139,8 @@ public final class Phone { */ private final int mTargetSdkVersion; + private final Object mLock = new Object(); + Phone(InCallAdapter adapter, String callingPackage, int targetSdkVersion) { mInCallAdapter = adapter; mCallingPackage = callingPackage; @@ -156,8 +158,12 @@ public final class Phone { if (call == null) { call = new Call(this, parcelableCall.getId(), mInCallAdapter, parcelableCall.getState(), mCallingPackage, mTargetSdkVersion); - mCallByTelecomCallId.put(parcelableCall.getId(), call); - mCalls.add(call); + + synchronized (mLock) { + mCallByTelecomCallId.put(parcelableCall.getId(), call); + mCalls.add(call); + } + checkCallTree(parcelableCall); call.internalUpdate(parcelableCall, mCallByTelecomCallId); fireCallAdded(call); @@ -169,8 +175,10 @@ public final class Phone { } final void internalRemoveCall(Call call) { - mCallByTelecomCallId.remove(call.internalGetCallId()); - mCalls.remove(call); + synchronized (mLock) { + mCallByTelecomCallId.remove(call.internalGetCallId()); + mCalls.remove(call); + } InCallService.VideoCall videoCall = call.getVideoCall(); if (videoCall != null) { diff --git a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java index 125296540688..3c799e0bfeea 100644 --- a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java +++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java @@ -26,7 +26,6 @@ import android.content.pm.ResolveInfo; import android.os.Binder; import android.os.Bundle; import android.os.PersistableBundle; -import android.os.RemoteException; import android.os.SystemProperties; import android.telephony.TelephonyManager; @@ -74,11 +73,6 @@ public final class TelephonyUtils { return cur == null ? Collections.emptyList() : cur; } - /** Throws a {@link RuntimeException} that wrapps the {@link RemoteException}. */ - public static RuntimeException rethrowAsRuntimeException(RemoteException remoteException) { - throw new RuntimeException(remoteException); - } - /** * Returns a {@link ComponentInfo} from the {@link ResolveInfo}, * or throws an {@link IllegalStateException} if not available. diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 9954de2da67e..f01519f934f3 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -286,6 +286,21 @@ public class CarrierConfigManager { "call_barring_default_service_class_int"; /** + * This carrier supports dialing USSD codes to enable/disable supplementary services such as + * call forwarding and call waiting over CDMA. + * <p> + * The supplementary service menu will still need to be set as visible, see + * {@link #KEY_CALL_FORWARDING_VISIBILITY_BOOL} and + * {@link #KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL}. + * <p> + * If this is set as false and the supplementary service menu is visible, the associated setting + * will be enabled and disabled based on the availability of supplementary services over UT. See + * {@link #KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL}. + * @hide + */ + public static final String KEY_SUPPORT_SS_OVER_CDMA_BOOL = "support_ss_over_cdma_bool"; + + /** * Flag indicating whether the Phone app should ignore EVENT_SIM_NETWORK_LOCKED * events from the Sim. * If true, this will prevent the IccNetworkDepersonalizationPanel from being shown, and @@ -5120,6 +5135,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL, true); sDefaults.putBoolean(KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL, true); sDefaults.putInt(KEY_CALL_BARRING_DEFAULT_SERVICE_CLASS_INT, SERVICE_CLASS_VOICE); + sDefaults.putBoolean(KEY_SUPPORT_SS_OVER_CDMA_BOOL, false); sDefaults.putBoolean(KEY_CALL_FORWARDING_VISIBILITY_BOOL, true); sDefaults.putBoolean(KEY_CALL_FORWARDING_WHEN_UNREACHABLE_SUPPORTED_BOOL, true); sDefaults.putBoolean(KEY_CALL_FORWARDING_WHEN_UNANSWERED_SUPPORTED_BOOL, true); diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java index b7a6d0ff7607..7c7dc4d79e9a 100644 --- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java +++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java @@ -23,6 +23,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; @@ -50,6 +51,7 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.annotation.NonNull; @@ -99,6 +101,7 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import java.io.FileNotFoundException; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; @@ -227,6 +230,7 @@ public class VcnManagementServiceTest { setupMockedCarrierPrivilege(true); mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps); + setupActiveSubscription(TEST_UUID_1); doReturn(mMockIBinder).when(mMockPolicyListener).asBinder(); doReturn(mMockIBinder).when(mMockStatusCallback).asBinder(); @@ -300,23 +304,65 @@ public class VcnManagementServiceTest { } private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot( - Set<ParcelUuid> activeSubscriptionGroups) { + ParcelUuid activeDataSubGrp, Set<ParcelUuid> activeSubscriptionGroups) { return triggerSubscriptionTrackerCbAndGetSnapshot( - activeSubscriptionGroups, Collections.emptyMap()); + activeDataSubGrp, activeSubscriptionGroups, Collections.emptyMap()); } private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot( - Set<ParcelUuid> activeSubscriptionGroups, Map<Integer, ParcelUuid> subIdToGroupMap) { + ParcelUuid activeDataSubGrp, + Set<ParcelUuid> activeSubscriptionGroups, + Map<Integer, ParcelUuid> subIdToGroupMap) { + return triggerSubscriptionTrackerCbAndGetSnapshot( + activeDataSubGrp, + activeSubscriptionGroups, + subIdToGroupMap, + true /* hasCarrierPrivileges */); + } + + private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot( + ParcelUuid activeDataSubGrp, + Set<ParcelUuid> activeSubscriptionGroups, + Map<Integer, ParcelUuid> subIdToGroupMap, + boolean hasCarrierPrivileges) { return triggerSubscriptionTrackerCbAndGetSnapshot( - activeSubscriptionGroups, subIdToGroupMap, true /* hasCarrierPrivileges */); + TEST_SUBSCRIPTION_ID, + activeDataSubGrp, + activeSubscriptionGroups, + subIdToGroupMap, + hasCarrierPrivileges); } private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot( + int activeDataSubId, + ParcelUuid activeDataSubGrp, + Set<ParcelUuid> activeSubscriptionGroups, + Map<Integer, ParcelUuid> subIdToGroupMap, + boolean hasCarrierPrivileges) { + final TelephonySubscriptionSnapshot snapshot = + buildSubscriptionSnapshot( + activeDataSubId, + activeDataSubGrp, + activeSubscriptionGroups, + subIdToGroupMap, + hasCarrierPrivileges); + + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); + cb.onNewSnapshot(snapshot); + + return snapshot; + } + + private TelephonySubscriptionSnapshot buildSubscriptionSnapshot( + int activeDataSubId, + ParcelUuid activeDataSubGrp, Set<ParcelUuid> activeSubscriptionGroups, Map<Integer, ParcelUuid> subIdToGroupMap, boolean hasCarrierPrivileges) { final TelephonySubscriptionSnapshot snapshot = mock(TelephonySubscriptionSnapshot.class); doReturn(activeSubscriptionGroups).when(snapshot).getActiveSubscriptionGroups(); + doReturn(activeDataSubGrp).when(snapshot).getActiveDataSubscriptionGroup(); + doReturn(activeDataSubId).when(snapshot).getActiveDataSubscriptionId(); final Set<String> privilegedPackages = (activeSubscriptionGroups == null || activeSubscriptionGroups.isEmpty()) @@ -343,12 +389,19 @@ public class VcnManagementServiceTest { return subIds; }).when(snapshot).getAllSubIdsInGroup(any()); - final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); - cb.onNewSnapshot(snapshot); - return snapshot; } + private void setupActiveSubscription(ParcelUuid activeDataSubGrp) { + mVcnMgmtSvc.setLastSnapshot( + buildSubscriptionSnapshot( + TEST_SUBSCRIPTION_ID, + activeDataSubGrp, + Collections.emptySet(), + Collections.emptyMap(), + true /* hasCarrierPrivileges */)); + } + private TelephonySubscriptionTrackerCallback getTelephonySubscriptionTrackerCallback() { final ArgumentCaptor<TelephonySubscriptionTrackerCallback> captor = ArgumentCaptor.forClass(TelephonySubscriptionTrackerCallback.class); @@ -372,25 +425,56 @@ public class VcnManagementServiceTest { @Test public void testTelephonyNetworkTrackerCallbackStartsInstances() throws Exception { + // Add a record for a non-active SIM + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + TelephonySubscriptionSnapshot snapshot = - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); + triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_UUID_1, new ArraySet<>(Arrays.asList(TEST_UUID_1, TEST_UUID_2))); verify(mMockDeps) .newVcnContext( eq(mMockContext), eq(mTestLooper.getLooper()), any(VcnNetworkProvider.class), anyBoolean()); + + // Verify that only the VCN for the active data SIM was started. verify(mMockDeps) .newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG), eq(snapshot), any()); + verify(mMockDeps, never()) + .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), eq(snapshot), any()); + } + + @Test + public void testTelephonyNetworkTrackerCallbackSwitchingActiveDataStartsAndStopsInstances() + throws Exception { + // Add a record for a non-active SIM + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + final Vcn vcn = startAndGetVcnInstance(TEST_UUID_1); + + TelephonySubscriptionSnapshot snapshot = + triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_UUID_2, new ArraySet<>(Arrays.asList(TEST_UUID_1, TEST_UUID_2))); + + // Verify that a new VCN for UUID_2 was started, and the old instance was torn down + // immediately + verify(mMockDeps) + .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), eq(snapshot), any()); + verify(vcn).teardownAsynchronously(); + assertEquals(1, mVcnMgmtSvc.getAllVcns().size()); + assertFalse(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_1)); + assertTrue(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_2)); } @Test public void testTelephonyNetworkTrackerCallbackStopsInstances() throws Exception { + setupActiveSubscription(TEST_UUID_2); + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet()); + triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet()); // Verify teardown after delay mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); @@ -400,19 +484,76 @@ public class VcnManagementServiceTest { } @Test + public void testTelephonyNetworkTrackerCallbackSwitchToNewSubscriptionImmediatelyTearsDown() + throws Exception { + setupActiveSubscription(TEST_UUID_2); + + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); + final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); + + // Simulate switch to different default data subscription that does not have a VCN. + triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_SUBSCRIPTION_ID, + null /* activeDataSubscriptionGroup */, + Collections.emptySet(), + Collections.emptyMap(), + false /* hasCarrierPrivileges */); + mTestLooper.dispatchAll(); + + verify(vcn).teardownAsynchronously(); + assertEquals(0, mVcnMgmtSvc.getAllVcns().size()); + } + + /** + * Tests an intermediate state where carrier privileges are marked as lost before active data + * subId changes during a SIM ejection. + * + * <p>The expected outcome is that the VCN is torn down after a delay, as opposed to + * immediately. + */ + @Test + public void testTelephonyNetworkTrackerCallbackLostCarrierPrivilegesBeforeActiveDataSubChanges() + throws Exception { + setupActiveSubscription(TEST_UUID_2); + + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); + final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); + + // Simulate privileges lost + triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_SUBSCRIPTION_ID, + TEST_UUID_2, + Collections.emptySet(), + Collections.emptyMap(), + false /* hasCarrierPrivileges */); + + // Verify teardown after delay + mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); + mTestLooper.dispatchAll(); + verify(vcn).teardownAsynchronously(); + } + + @Test public void testTelephonyNetworkTrackerCallbackSimSwitchesDoNotKillVcnInstances() throws Exception { + setupActiveSubscription(TEST_UUID_2); + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); // Simulate SIM unloaded - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet()); + triggerSubscriptionTrackerCbAndGetSnapshot( + INVALID_SUBSCRIPTION_ID, + null /* activeDataSubscriptionGroup */, + Collections.emptySet(), + Collections.emptyMap(), + false /* hasCarrierPrivileges */); // Simulate new SIM loaded right during teardown delay. mTestLooper.moveTimeForward( VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2); mTestLooper.dispatchAll(); - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2)); + triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2)); // Verify that even after the full timeout duration, the VCN instance is not torn down mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); @@ -422,11 +563,13 @@ public class VcnManagementServiceTest { @Test public void testTelephonyNetworkTrackerCallbackDoesNotKillNewVcnInstances() throws Exception { + setupActiveSubscription(TEST_UUID_2); + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); final Vcn oldInstance = startAndGetVcnInstance(TEST_UUID_2); // Simulate SIM unloaded - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet()); + triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet()); // Config cleared, SIM reloaded & config re-added right before teardown delay, staring new // vcnInstance. @@ -434,6 +577,7 @@ public class VcnManagementServiceTest { VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2); mTestLooper.dispatchAll(); mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME); + triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2)); final Vcn newInstance = startAndGetVcnInstance(TEST_UUID_2); // Verify that new instance was different, and the old one was torn down @@ -538,6 +682,31 @@ public class VcnManagementServiceTest { } @Test + public void testSetVcnConfigNonActiveSimDoesNotStartVcn() throws Exception { + // Use a different UUID to simulate a new VCN config. + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + assertEquals(TEST_VCN_CONFIG, mVcnMgmtSvc.getConfigs().get(TEST_UUID_2)); + verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); + + verify(mMockDeps, never()).newVcn(any(), any(), any(), any(), any()); + } + + @Test + public void testSetVcnConfigActiveSimTearsDownExistingVcnsImmediately() throws Exception { + final Vcn vcn = startAndGetVcnInstance(TEST_UUID_1); + + // Use a different UUID to simulate a new VCN config. + setupActiveSubscription(TEST_UUID_2); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + + verify(mMockDeps, times(2)).newVcn(any(), any(), any(), any(), any()); + verify(vcn).teardownAsynchronously(); + assertEquals(1, mVcnMgmtSvc.getAllVcns().size()); + assertFalse(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_1)); + assertTrue(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_2)); + } + + @Test public void testSetVcnConfigTestModeRequiresPermission() throws Exception { doThrow(new SecurityException("Requires MANAGE_TEST_NETWORKS")) .when(mMockContext) @@ -561,7 +730,7 @@ public class VcnManagementServiceTest { @Test public void testSetVcnConfigNotifiesStatusCallback() throws Exception { - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2)); + triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2)); mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME); verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED); @@ -635,7 +804,9 @@ public class VcnManagementServiceTest { } @Test - public void testSetVcnConfigClearVcnConfigStartsUpdatesAndTeardsDownVcns() throws Exception { + public void testSetVcnConfigClearVcnConfigStartsUpdatesAndTearsDownVcns() throws Exception { + setupActiveSubscription(TEST_UUID_2); + // Use a different UUID to simulate a new VCN config. mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); final Map<ParcelUuid, Vcn> vcnInstances = mVcnMgmtSvc.getAllVcns(); @@ -646,12 +817,7 @@ public class VcnManagementServiceTest { // Verify Vcn is started verify(mMockDeps) - .newVcn( - eq(mVcnContext), - eq(TEST_UUID_2), - eq(TEST_VCN_CONFIG), - eq(TelephonySubscriptionSnapshot.EMPTY_SNAPSHOT), - any()); + .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), any(), any()); // Verify Vcn is updated if it was previously started mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); @@ -693,7 +859,7 @@ public class VcnManagementServiceTest { // Assert that if both UUID 1 and 2 are provisioned, the caller only gets ones that they are // privileged for. - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); + triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1)); final List<ParcelUuid> subGrps = mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME); assertEquals(Collections.singletonList(TEST_UUID_1), subGrps); @@ -760,6 +926,7 @@ public class VcnManagementServiceTest { int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges) { mVcnMgmtSvc.systemReady(); triggerSubscriptionTrackerCbAndGetSnapshot( + subGrp, Collections.singleton(subGrp), Collections.singletonMap(subId, subGrp), hasCarrierPrivileges); @@ -927,18 +1094,23 @@ public class VcnManagementServiceTest { @Test public void testSubscriptionSnapshotUpdateNotifiesVcn() { + setupActiveSubscription(TEST_UUID_2); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); final Map<ParcelUuid, Vcn> vcnInstances = mVcnMgmtSvc.getAllVcns(); final Vcn vcnInstance = vcnInstances.get(TEST_UUID_2); TelephonySubscriptionSnapshot snapshot = - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2)); + triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_UUID_2, Collections.singleton(TEST_UUID_2)); verify(vcnInstance).updateSubscriptionSnapshot(eq(snapshot)); } @Test public void testAddNewVcnUpdatesPolicyListener() throws Exception { + setupActiveSubscription(TEST_UUID_2); + mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); @@ -948,6 +1120,8 @@ public class VcnManagementServiceTest { @Test public void testRemoveVcnUpdatesPolicyListener() throws Exception { + setupActiveSubscription(TEST_UUID_2); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); @@ -958,10 +1132,13 @@ public class VcnManagementServiceTest { @Test public void testVcnSubIdChangeUpdatesPolicyListener() throws Exception { + setupActiveSubscription(TEST_UUID_2); + startAndGetVcnInstance(TEST_UUID_2); mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_UUID_2, Collections.singleton(TEST_UUID_2), Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_2)); @@ -988,7 +1165,8 @@ public class VcnManagementServiceTest { private void verifyVcnSafeModeChangesNotifiesPolicyListeners(boolean enterSafeMode) throws Exception { TelephonySubscriptionSnapshot snapshot = - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); + triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_UUID_1, Collections.singleton(TEST_UUID_1)); mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); @@ -1014,7 +1192,8 @@ public class VcnManagementServiceTest { boolean hasPermissionsforSubGroup) throws Exception { TelephonySubscriptionSnapshot snapshot = - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(subGroup)); + triggerSubscriptionTrackerCbAndGetSnapshot( + subGroup, Collections.singleton(subGroup)); setupSubscriptionAndStartVcn( TEST_SUBSCRIPTION_ID, subGroup, true /* isActive */, hasPermissionsforSubGroup); @@ -1089,6 +1268,7 @@ public class VcnManagementServiceTest { // timeout so the VCN goes inactive. final TelephonySubscriptionSnapshot snapshot = triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_UUID_1, Collections.singleton(TEST_UUID_1), Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_1), false /* hasCarrierPrivileges */); diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java index ca7463884d3a..1f0df62fe72c 100644 --- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java +++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -21,6 +21,7 @@ import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX; import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX; import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; @@ -54,6 +55,7 @@ import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.util.ArraySet; @@ -178,6 +180,14 @@ public class TelephonySubscriptionTrackerTest { return captor.getValue(); } + private ActiveDataSubscriptionIdListener getActiveDataSubscriptionIdListener() { + final ArgumentCaptor<TelephonyCallback> captor = + ArgumentCaptor.forClass(TelephonyCallback.class); + verify(mTelephonyManager).registerTelephonyCallback(any(), captor.capture()); + + return (ActiveDataSubscriptionIdListener) captor.getValue(); + } + private Intent buildTestBroadcastIntent(boolean hasValidSubscription) { Intent intent = new Intent(ACTION_CARRIER_CONFIG_CHANGED); intent.putExtra(EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX); @@ -196,7 +206,14 @@ public class TelephonySubscriptionTrackerTest { private TelephonySubscriptionSnapshot buildExpectedSnapshot( Map<Integer, SubscriptionInfo> subIdToInfoMap, Map<ParcelUuid, Set<String>> privilegedPackages) { - return new TelephonySubscriptionSnapshot(subIdToInfoMap, privilegedPackages); + return new TelephonySubscriptionSnapshot(0, subIdToInfoMap, privilegedPackages); + } + + private TelephonySubscriptionSnapshot buildExpectedSnapshot( + int activeSubId, + Map<Integer, SubscriptionInfo> subIdToInfoMap, + Map<ParcelUuid, Set<String>> privilegedPackages) { + return new TelephonySubscriptionSnapshot(activeSubId, subIdToInfoMap, privilegedPackages); } private void verifyNoActiveSubscriptions() { @@ -250,6 +267,26 @@ public class TelephonySubscriptionTrackerTest { } @Test + public void testOnSubscriptionsChangedFired_onActiveSubIdsChanged() throws Exception { + setupReadySubIds(); + setPrivilegedPackagesForMock(Collections.emptyList()); + + doReturn(TEST_SUBSCRIPTION_ID_2).when(mDeps).getActiveDataSubscriptionId(); + final ActiveDataSubscriptionIdListener listener = getActiveDataSubscriptionIdListener(); + listener.onActiveDataSubscriptionIdChanged(TEST_SUBSCRIPTION_ID_2); + mTestLooper.dispatchAll(); + + ArgumentCaptor<TelephonySubscriptionSnapshot> snapshotCaptor = + ArgumentCaptor.forClass(TelephonySubscriptionSnapshot.class); + verify(mCallback).onNewSnapshot(snapshotCaptor.capture()); + + TelephonySubscriptionSnapshot snapshot = snapshotCaptor.getValue(); + assertNotNull(snapshot); + assertEquals(TEST_SUBSCRIPTION_ID_2, snapshot.getActiveDataSubscriptionId()); + assertEquals(TEST_PARCEL_UUID, snapshot.getActiveDataSubscriptionGroup()); + } + + @Test public void testOnSubscriptionsChangedFired_WithReadySubidsNoPrivilegedPackages() throws Exception { setupReadySubIds(); @@ -371,7 +408,8 @@ public class TelephonySubscriptionTrackerTest { @Test public void testTelephonySubscriptionSnapshotGetGroupForSubId() throws Exception { final TelephonySubscriptionSnapshot snapshot = - new TelephonySubscriptionSnapshot(TEST_SUBID_TO_INFO_MAP, emptyMap()); + new TelephonySubscriptionSnapshot( + TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap()); assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_1)); assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_2)); @@ -380,7 +418,8 @@ public class TelephonySubscriptionTrackerTest { @Test public void testTelephonySubscriptionSnapshotGetAllSubIdsInGroup() throws Exception { final TelephonySubscriptionSnapshot snapshot = - new TelephonySubscriptionSnapshot(TEST_SUBID_TO_INFO_MAP, emptyMap()); + new TelephonySubscriptionSnapshot( + TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap()); assertEquals( new ArraySet<>(Arrays.asList(TEST_SUBSCRIPTION_ID_1, TEST_SUBSCRIPTION_ID_2)), diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index b97023a95d72..a696b3ae28f7 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -127,7 +127,9 @@ public class VcnGatewayConnectionTestBase { protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT = new TelephonySubscriptionSnapshot( - Collections.singletonMap(TEST_SUB_ID, TEST_SUB_INFO), Collections.EMPTY_MAP); + TEST_SUB_ID, + Collections.singletonMap(TEST_SUB_ID, TEST_SUB_INFO), + Collections.EMPTY_MAP); @NonNull protected final Context mContext; @NonNull protected final TestLooper mTestLooper; diff --git a/tools/aapt2/AppInfo.h b/tools/aapt2/AppInfo.h index d3ca357b0305..cabbe7ea7446 100644 --- a/tools/aapt2/AppInfo.h +++ b/tools/aapt2/AppInfo.h @@ -17,11 +17,10 @@ #ifndef AAPT_APP_INFO_H #define AAPT_APP_INFO_H +#include <optional> #include <set> #include <string> -#include "util/Maybe.h" - namespace aapt { // Information relevant to building an app, parsed from the app's AndroidManifest.xml. @@ -30,19 +29,19 @@ struct AppInfo { std::string package; // The app's minimum SDK version, if it is defined. - Maybe<int> min_sdk_version; + std::optional<int> min_sdk_version; // The app's version code (the lower 32 bits of the long version code), if it is defined. - Maybe<uint32_t> version_code; + std::optional<uint32_t> version_code; // The app's version code major (the upper 32 bits of the long version code), if it is defined. - Maybe<uint32_t> version_code_major; + std::optional<uint32_t> version_code_major; // The app's revision code, if it is defined. - Maybe<uint32_t> revision_code; + std::optional<uint32_t> revision_code; // The app's split name, if it is a split. - Maybe<std::string> split_name; + std::optional<std::string> split_name; // The split names that this split depends on. std::set<std::string> split_name_dependencies; diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp index ef3a62f4efcc..df444ba7b169 100644 --- a/tools/aapt2/Debug.cpp +++ b/tools/aapt2/Debug.cpp @@ -280,8 +280,7 @@ void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions& printer->Indent(); for (const ResourceTableEntryView& entry : type.entries) { printer->Print("resource "); - printer->Print(ResourceId(package.id.value_or_default(0), type.id.value_or_default(0), - entry.id.value_or_default(0)) + printer->Print(ResourceId(package.id.value_or(0), type.id.value_or(0), entry.id.value_or(0)) .to_string()); printer->Print(" "); @@ -362,7 +361,7 @@ void Debug::PrintStyleGraph(ResourceTable* table, const ResourceName& target_sty continue; } - Maybe<ResourceTable::SearchResult> result = table->FindResource(style_name); + std::optional<ResourceTable::SearchResult> result = table->FindResource(style_name); if (result) { ResourceEntry* entry = result.value().entry; for (const auto& value : entry->values) { @@ -482,8 +481,7 @@ class XmlPrinter : public xml::ConstVisitor { if (attr.compiled_attribute) { printer_->Print("("); - printer_->Print( - attr.compiled_attribute.value().id.value_or_default(ResourceId(0)).to_string()); + printer_->Print(attr.compiled_attribute.value().id.value_or(ResourceId(0)).to_string()); printer_->Print(")"); } printer_->Print("="); diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp index 8a43bb4ede35..b249c6c128e1 100644 --- a/tools/aapt2/Main.cpp +++ b/tools/aapt2/Main.cpp @@ -147,7 +147,7 @@ class DaemonCommand : public Command { private: io::FileOutputStream* out_; IDiagnostics* diagnostics_; - Maybe<std::string> trace_folder_; + std::optional<std::string> trace_folder_; }; } // namespace aapt diff --git a/tools/aapt2/NameMangler.h b/tools/aapt2/NameMangler.h index f1aad29a5c58..0b4905253d20 100644 --- a/tools/aapt2/NameMangler.h +++ b/tools/aapt2/NameMangler.h @@ -21,7 +21,6 @@ #include <string> #include "Resource.h" -#include "util/Maybe.h" namespace aapt { @@ -44,7 +43,7 @@ class NameMangler { public: explicit NameMangler(NameManglerPolicy policy) : policy_(policy) {} - Maybe<ResourceName> MangleName(const ResourceName& name) { + std::optional<ResourceName> MangleName(const ResourceName& name) { if (policy_.target_package_name == name.package || policy_.packages_to_mangle.count(name.package) == 0) { return {}; diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp index f1e2da9f41e2..f49c25483e3b 100644 --- a/tools/aapt2/ResourceParser.cpp +++ b/tools/aapt2/ResourceParser.cpp @@ -20,7 +20,8 @@ #include <limits> #include <sstream> -#include "android-base/logging.h" +#include <android-base/logging.h> +#include <idmap2/Policies.h> #include "ResourceTable.h" #include "ResourceUtils.h" @@ -28,12 +29,10 @@ #include "ValueVisitor.h" #include "text/Utf8Iterator.h" #include "util/ImmutableMap.h" -#include "util/Maybe.h" + #include "util/Util.h" #include "xml/XmlPullParser.h" -#include "idmap2/Policies.h" - using ::aapt::ResourceUtils::StringBuilder; using ::aapt::text::Utf8Iterator; using ::android::ConfigDescription; @@ -109,8 +108,8 @@ struct ParsedResource { Visibility::Level visibility_level = Visibility::Level::kUndefined; bool staged_api = false; bool allow_new = false; - Maybe<OverlayableItem> overlayable_item; - Maybe<StagedId> staged_alias; + std::optional<OverlayableItem> overlayable_item; + std::optional<StagedId> staged_alias; std::string comment; std::unique_ptr<Value> value; @@ -252,7 +251,7 @@ bool ResourceParser::FlattenXmlSubtree( std::string current_text; // The first occurrence of a <xliff:g> tag. Nested <xliff:g> tags are illegal. - Maybe<size_t> untranslatable_start_depth; + std::optional<size_t> untranslatable_start_depth; Node root; std::vector<Node*> node_stack; @@ -342,7 +341,7 @@ bool ResourceParser::FlattenXmlSubtree( } node_stack.pop_back(); - if (untranslatable_start_depth == make_value(depth)) { + if (untranslatable_start_depth == depth) { // This is the end of an untranslatable section. untranslatable_start_depth = {}; } @@ -468,7 +467,7 @@ bool ResourceParser::ParseResources(xml::XmlPullParser* parser) { } // Extract the product name if it exists. - if (Maybe<StringPiece> maybe_product = xml::FindNonEmptyAttribute(parser, "product")) { + if (std::optional<StringPiece> maybe_product = xml::FindNonEmptyAttribute(parser, "product")) { parsed_resource.product = maybe_product.value().to_string(); } @@ -560,7 +559,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, resource_format = android::ResTable_map::TYPE_ANY; // Items have their type encoded in the type attribute. - if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) { + if (std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) { resource_type = maybe_type.value().to_string(); } else { diag_->Error(DiagMessage(source_.WithLine(parser->line_number())) @@ -568,7 +567,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, return false; } - if (Maybe<StringPiece> maybe_format = xml::FindNonEmptyAttribute(parser, "format")) { + if (std::optional<StringPiece> maybe_format = xml::FindNonEmptyAttribute(parser, "format")) { // An explicit format for this resource was specified. The resource will // retain its type in its name, but the accepted value for this type is // overridden. @@ -584,7 +583,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, can_be_item = false; // Bags have their type encoded in the type attribute. - if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) { + if (std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) { resource_type = maybe_type.value().to_string(); } else { diag_->Error(DiagMessage(source_.WithLine(parser->line_number())) @@ -595,7 +594,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, // Get the name of the resource. This will be checked later, because not all // XML elements require a name. - Maybe<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name"); + std::optional<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name"); if (resource_type == "id") { if (!maybe_name) { @@ -835,10 +834,8 @@ std::unique_ptr<Item> ResourceParser::ParseXml(const FlattenedXmlSubTree& xmlsub bool ResourceParser::ParseString(xml::XmlPullParser* parser, ParsedResource* out_resource) { bool formatted = true; - if (Maybe<StringPiece> formatted_attr = - xml::FindAttribute(parser, "formatted")) { - Maybe<bool> maybe_formatted = - ResourceUtils::ParseBool(formatted_attr.value()); + if (std::optional<StringPiece> formatted_attr = xml::FindAttribute(parser, "formatted")) { + std::optional<bool> maybe_formatted = ResourceUtils::ParseBool(formatted_attr.value()); if (!maybe_formatted) { diag_->Error(DiagMessage(out_resource->source) << "invalid value for 'formatted'. Must be a boolean"); @@ -848,8 +845,8 @@ bool ResourceParser::ParseString(xml::XmlPullParser* parser, } bool translatable = options_.translatable; - if (Maybe<StringPiece> translatable_attr = xml::FindAttribute(parser, "translatable")) { - Maybe<bool> maybe_translatable = ResourceUtils::ParseBool(translatable_attr.value()); + if (std::optional<StringPiece> translatable_attr = xml::FindAttribute(parser, "translatable")) { + std::optional<bool> maybe_translatable = ResourceUtils::ParseBool(translatable_attr.value()); if (!maybe_translatable) { diag_->Error(DiagMessage(out_resource->source) << "invalid value for 'translatable'. Must be a boolean"); @@ -929,7 +926,7 @@ bool ResourceParser::ParsePublic(xml::XmlPullParser* parser, ParsedResource* out << "ignoring configuration '" << out_resource->config << "' for <public> tag"); } - Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type"); + std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type"); if (!maybe_type) { diag_->Error(DiagMessage(out_resource->source) << "<public> must have a 'type' attribute"); @@ -946,8 +943,8 @@ bool ResourceParser::ParsePublic(xml::XmlPullParser* parser, ParsedResource* out out_resource->name.type = *parsed_type; - if (Maybe<StringPiece> maybe_id_str = xml::FindNonEmptyAttribute(parser, "id")) { - Maybe<ResourceId> maybe_id = ResourceUtils::ParseResourceId(maybe_id_str.value()); + if (std::optional<StringPiece> maybe_id_str = xml::FindNonEmptyAttribute(parser, "id")) { + std::optional<ResourceId> maybe_id = ResourceUtils::ParseResourceId(maybe_id_str.value()); if (!maybe_id) { diag_->Error(DiagMessage(out_resource->source) << "invalid resource ID '" << maybe_id_str.value() << "' in <public>"); @@ -974,7 +971,7 @@ bool static ParseGroupImpl(xml::XmlPullParser* parser, ParsedResource* out_resou << "> tag"); } - Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type"); + std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type"); if (!maybe_type) { diag->Error(DiagMessage(out_resource->source) << "<" << tag_name << "> must have a 'type' attribute"); @@ -988,14 +985,14 @@ bool static ParseGroupImpl(xml::XmlPullParser* parser, ParsedResource* out_resou return false; } - Maybe<StringPiece> maybe_id_str = xml::FindNonEmptyAttribute(parser, "first-id"); + std::optional<StringPiece> maybe_id_str = xml::FindNonEmptyAttribute(parser, "first-id"); if (!maybe_id_str) { diag->Error(DiagMessage(out_resource->source) << "<" << tag_name << "> must have a 'first-id' attribute"); return false; } - Maybe<ResourceId> maybe_id = ResourceUtils::ParseResourceId(maybe_id_str.value()); + std::optional<ResourceId> maybe_id = ResourceUtils::ParseResourceId(maybe_id_str.value()); if (!maybe_id) { diag->Error(DiagMessage(out_resource->source) << "invalid resource ID '" << maybe_id_str.value() << "' in <" << tag_name << ">"); @@ -1090,7 +1087,7 @@ bool ResourceParser::ParsePublicGroup(xml::XmlPullParser* parser, ParsedResource bool ResourceParser::ParseSymbolImpl(xml::XmlPullParser* parser, ParsedResource* out_resource) { - Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type"); + std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type"); if (!maybe_type) { diag_->Error(DiagMessage(out_resource->source) << "<" << parser->element_name() @@ -1137,7 +1134,7 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource << "' for <overlayable> tag"); } - Maybe<StringPiece> overlayable_name = xml::FindNonEmptyAttribute(parser, "name"); + std::optional<StringPiece> overlayable_name = xml::FindNonEmptyAttribute(parser, "name"); if (!overlayable_name) { diag_->Error(DiagMessage(out_resource->source) << "<overlayable> tag must have a 'name' attribute"); @@ -1146,7 +1143,7 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource const std::string kActorUriScheme = android::base::StringPrintf("%s://", Overlayable::kActorScheme); - Maybe<StringPiece> overlayable_actor = xml::FindNonEmptyAttribute(parser, "actor"); + std::optional<StringPiece> overlayable_actor = xml::FindNonEmptyAttribute(parser, "actor"); if (overlayable_actor && !util::StartsWith(overlayable_actor.value(), kActorUriScheme)) { diag_->Error(DiagMessage(out_resource->source) << "specified <overlayable> tag 'actor' attribute must use the scheme '" @@ -1194,7 +1191,7 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource } // Items specify the name and type of resource that should be overlayable - Maybe<StringPiece> item_name = xml::FindNonEmptyAttribute(parser, "name"); + std::optional<StringPiece> item_name = xml::FindNonEmptyAttribute(parser, "name"); if (!item_name) { diag_->Error(DiagMessage(element_source) << "<item> within an <overlayable> must have a 'name' attribute"); @@ -1202,7 +1199,7 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource continue; } - Maybe<StringPiece> item_type = xml::FindNonEmptyAttribute(parser, "type"); + std::optional<StringPiece> item_type = xml::FindNonEmptyAttribute(parser, "type"); if (!item_type) { diag_->Error(DiagMessage(element_source) << "<item> within an <overlayable> must have a 'type' attribute"); @@ -1236,7 +1233,8 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource diag_->Error(DiagMessage(element_source) << "<policy> blocks cannot be recursively nested"); error = true; break; - } else if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) { + } else if (std::optional<StringPiece> maybe_type = + xml::FindNonEmptyAttribute(parser, "type")) { // Parse the polices separated by vertical bar characters to allow for specifying multiple // policies. Items within the policy tag will have the specified policy. for (const StringPiece& part : util::Tokenize(maybe_type.value(), '|')) { @@ -1302,7 +1300,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser, uint32_t type_mask = 0; - Maybe<StringPiece> maybe_format = xml::FindAttribute(parser, "format"); + std::optional<StringPiece> maybe_format = xml::FindAttribute(parser, "format"); if (maybe_format) { type_mask = ParseFormatAttribute(maybe_format.value()); if (type_mask == 0) { @@ -1312,9 +1310,9 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser, } } - Maybe<int32_t> maybe_min, maybe_max; + std::optional<int32_t> maybe_min, maybe_max; - if (Maybe<StringPiece> maybe_min_str = xml::FindAttribute(parser, "min")) { + if (std::optional<StringPiece> maybe_min_str = xml::FindAttribute(parser, "min")) { StringPiece min_str = util::TrimWhitespace(maybe_min_str.value()); if (!min_str.empty()) { std::u16string min_str16 = util::Utf8ToUtf16(min_str); @@ -1331,7 +1329,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser, } } - if (Maybe<StringPiece> maybe_max_str = xml::FindAttribute(parser, "max")) { + if (std::optional<StringPiece> maybe_max_str = xml::FindAttribute(parser, "max")) { StringPiece max_str = util::TrimWhitespace(maybe_max_str.value()); if (!max_str.empty()) { std::u16string max_str16 = util::Utf8ToUtf16(max_str); @@ -1398,8 +1396,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser, type_mask |= android::ResTable_map::TYPE_FLAGS; } - if (Maybe<Attribute::Symbol> s = - ParseEnumOrFlagItem(parser, element_name)) { + if (std::optional<Attribute::Symbol> s = ParseEnumOrFlagItem(parser, element_name)) { Attribute::Symbol& symbol = s.value(); ParsedResource child_resource; child_resource.name = symbol.symbol.name.value(); @@ -1443,24 +1440,24 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser, type_mask ? type_mask : uint32_t{android::ResTable_map::TYPE_ANY}); attr->SetWeak(weak); attr->symbols = std::vector<Attribute::Symbol>(items.begin(), items.end()); - attr->min_int = maybe_min.value_or_default(std::numeric_limits<int32_t>::min()); - attr->max_int = maybe_max.value_or_default(std::numeric_limits<int32_t>::max()); + attr->min_int = maybe_min.value_or(std::numeric_limits<int32_t>::min()); + attr->max_int = maybe_max.value_or(std::numeric_limits<int32_t>::max()); out_resource->value = std::move(attr); return true; } -Maybe<Attribute::Symbol> ResourceParser::ParseEnumOrFlagItem( - xml::XmlPullParser* parser, const StringPiece& tag) { +std::optional<Attribute::Symbol> ResourceParser::ParseEnumOrFlagItem(xml::XmlPullParser* parser, + const StringPiece& tag) { const Source source = source_.WithLine(parser->line_number()); - Maybe<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name"); + std::optional<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name"); if (!maybe_name) { diag_->Error(DiagMessage(source) << "no attribute 'name' found for tag <" << tag << ">"); return {}; } - Maybe<StringPiece> maybe_value = xml::FindNonEmptyAttribute(parser, "value"); + std::optional<StringPiece> maybe_value = xml::FindNonEmptyAttribute(parser, "value"); if (!maybe_value) { diag_->Error(DiagMessage(source) << "no attribute 'value' found for tag <" << tag << ">"); @@ -1484,13 +1481,13 @@ Maybe<Attribute::Symbol> ResourceParser::ParseEnumOrFlagItem( bool ResourceParser::ParseStyleItem(xml::XmlPullParser* parser, Style* style) { const Source source = source_.WithLine(parser->line_number()); - Maybe<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name"); + std::optional<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name"); if (!maybe_name) { diag_->Error(DiagMessage(source) << "<item> must have a 'name' attribute"); return false; } - Maybe<Reference> maybe_key = ResourceUtils::ParseXmlAttributeName(maybe_name.value()); + std::optional<Reference> maybe_key = ResourceUtils::ParseXmlAttributeName(maybe_name.value()); if (!maybe_key) { diag_->Error(DiagMessage(source) << "invalid attribute name '" << maybe_name.value() << "'"); return false; @@ -1515,7 +1512,7 @@ bool ResourceParser::ParseStyle(const ResourceType type, xml::XmlPullParser* par std::unique_ptr<Style> style = util::make_unique<Style>(); - Maybe<StringPiece> maybe_parent = xml::FindAttribute(parser, "parent"); + std::optional<StringPiece> maybe_parent = xml::FindAttribute(parser, "parent"); if (maybe_parent) { // If the parent is empty, we don't have a parent, but we also don't infer either. if (!maybe_parent.value().empty()) { @@ -1571,7 +1568,7 @@ bool ResourceParser::ParseStyle(const ResourceType type, xml::XmlPullParser* par bool ResourceParser::ParseArray(xml::XmlPullParser* parser, ParsedResource* out_resource) { uint32_t resource_format = android::ResTable_map::TYPE_ANY; - if (Maybe<StringPiece> format_attr = xml::FindNonEmptyAttribute(parser, "format")) { + if (std::optional<StringPiece> format_attr = xml::FindNonEmptyAttribute(parser, "format")) { resource_format = ParseFormatTypeNoEnumsOrFlags(format_attr.value()); if (resource_format == 0u) { diag_->Error(DiagMessage(source_.WithLine(parser->line_number())) @@ -1598,8 +1595,8 @@ bool ResourceParser::ParseArrayImpl(xml::XmlPullParser* parser, std::unique_ptr<Array> array = util::make_unique<Array>(); bool translatable = options_.translatable; - if (Maybe<StringPiece> translatable_attr = xml::FindAttribute(parser, "translatable")) { - Maybe<bool> maybe_translatable = ResourceUtils::ParseBool(translatable_attr.value()); + if (std::optional<StringPiece> translatable_attr = xml::FindAttribute(parser, "translatable")) { + std::optional<bool> maybe_translatable = ResourceUtils::ParseBool(translatable_attr.value()); if (!maybe_translatable) { diag_->Error(DiagMessage(out_resource->source) << "invalid value for 'translatable'. Must be a boolean"); @@ -1664,8 +1661,7 @@ bool ResourceParser::ParsePlural(xml::XmlPullParser* parser, const std::string& element_namespace = parser->element_namespace(); const std::string& element_name = parser->element_name(); if (element_namespace.empty() && element_name == "item") { - Maybe<StringPiece> maybe_quantity = - xml::FindNonEmptyAttribute(parser, "quantity"); + std::optional<StringPiece> maybe_quantity = xml::FindNonEmptyAttribute(parser, "quantity"); if (!maybe_quantity) { diag_->Error(DiagMessage(item_source) << "<item> in <plurals> requires attribute " @@ -1767,7 +1763,7 @@ bool ResourceParser::ParseDeclareStyleable(xml::XmlPullParser* parser, const std::string& element_namespace = parser->element_namespace(); const std::string& element_name = parser->element_name(); if (element_namespace.empty() && element_name == "attr") { - Maybe<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name"); + std::optional<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name"); if (!maybe_name) { diag_->Error(DiagMessage(item_source) << "<attr> tag must have a 'name' attribute"); error = true; @@ -1777,7 +1773,7 @@ bool ResourceParser::ParseDeclareStyleable(xml::XmlPullParser* parser, // If this is a declaration, the package name may be in the name. Separate // these out. // Eg. <attr name="android:text" /> - Maybe<Reference> maybe_ref = ResourceUtils::ParseXmlAttributeName(maybe_name.value()); + std::optional<Reference> maybe_ref = ResourceUtils::ParseXmlAttributeName(maybe_name.value()); if (!maybe_ref) { diag_->Error(DiagMessage(item_source) << "<attr> tag has invalid name '" << maybe_name.value() << "'"); diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h index 261499781638..548f5f9531fd 100644 --- a/tools/aapt2/ResourceParser.h +++ b/tools/aapt2/ResourceParser.h @@ -18,6 +18,7 @@ #define AAPT_RESOURCE_PARSER_H #include <memory> +#include <optional> #include "android-base/macros.h" #include "androidfw/ConfigDescription.h" @@ -27,7 +28,6 @@ #include "ResourceTable.h" #include "ResourceValues.h" #include "StringPool.h" -#include "util/Maybe.h" #include "xml/XmlPullParser.h" namespace aapt { @@ -54,7 +54,7 @@ struct ResourceParserOptions { // If visibility was forced, we need to use it when creating a new resource and also error if we // try to parse the <public>, <public-group>, <java-symbol> or <symbol> tags. - Maybe<Visibility::Level> visibility; + std::optional<Visibility::Level> visibility; }; struct FlattenedXmlSubTree { @@ -122,8 +122,8 @@ class ResourceParser { bool ParseAddResource(xml::XmlPullParser* parser, ParsedResource* out_resource); bool ParseAttr(xml::XmlPullParser* parser, ParsedResource* out_resource); bool ParseAttrImpl(xml::XmlPullParser* parser, ParsedResource* out_resource, bool weak); - Maybe<Attribute::Symbol> ParseEnumOrFlagItem(xml::XmlPullParser* parser, - const android::StringPiece& tag); + std::optional<Attribute::Symbol> ParseEnumOrFlagItem(xml::XmlPullParser* parser, + const android::StringPiece& tag); bool ParseStyle(ResourceType type, xml::XmlPullParser* parser, ParsedResource* out_resource); bool ParseStyleItem(xml::XmlPullParser* parser, Style* style); bool ParseDeclareStyleable(xml::XmlPullParser* parser, ParsedResource* out_resource); diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp index 279ebcba2f71..556ffa221db5 100644 --- a/tools/aapt2/ResourceParser_test.cpp +++ b/tools/aapt2/ResourceParser_test.cpp @@ -567,12 +567,12 @@ TEST_F(ResourceParserTest, ParseStyle) { Style* style = test::GetValue<Style>(&table_, "style/foo"); ASSERT_THAT(style, NotNull()); ASSERT_TRUE(style->parent); - EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("style/fu")))); + EXPECT_THAT(style->parent.value().name, Eq(test::ParseNameOrDie("style/fu"))); ASSERT_THAT(style->entries, SizeIs(3)); - EXPECT_THAT(style->entries[0].key.name, Eq(make_value(test::ParseNameOrDie("attr/bar")))); - EXPECT_THAT(style->entries[1].key.name, Eq(make_value(test::ParseNameOrDie("attr/bat")))); - EXPECT_THAT(style->entries[2].key.name, Eq(make_value(test::ParseNameOrDie("attr/baz")))); + EXPECT_THAT(style->entries[0].key.name, Eq(test::ParseNameOrDie("attr/bar"))); + EXPECT_THAT(style->entries[1].key.name, Eq(test::ParseNameOrDie("attr/bat"))); + EXPECT_THAT(style->entries[2].key.name, Eq(test::ParseNameOrDie("attr/baz"))); } TEST_F(ResourceParserTest, ParseStyleWithShorthandParent) { @@ -581,7 +581,7 @@ TEST_F(ResourceParserTest, ParseStyleWithShorthandParent) { Style* style = test::GetValue<Style>(&table_, "style/foo"); ASSERT_THAT(style, NotNull()); ASSERT_TRUE(style->parent); - EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("com.app:style/Theme")))); + EXPECT_THAT(style->parent.value().name, Eq(test::ParseNameOrDie("com.app:style/Theme"))); } TEST_F(ResourceParserTest, ParseStyleWithPackageAliasedParent) { @@ -594,7 +594,7 @@ TEST_F(ResourceParserTest, ParseStyleWithPackageAliasedParent) { ASSERT_THAT(style, NotNull()); ASSERT_TRUE(style->parent); ASSERT_TRUE(style->parent.value().name); - EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("android:style/Theme")))); + EXPECT_THAT(style->parent.value().name, Eq(test::ParseNameOrDie("android:style/Theme"))); } TEST_F(ResourceParserTest, ParseStyleWithPackageAliasedItems) { @@ -607,7 +607,7 @@ TEST_F(ResourceParserTest, ParseStyleWithPackageAliasedItems) { Style* style = test::GetValue<Style>(&table_, "style/foo"); ASSERT_THAT(style, NotNull()); ASSERT_THAT(style->entries, SizeIs(1)); - EXPECT_THAT(style->entries[0].key.name, Eq(make_value(test::ParseNameOrDie("android:attr/bar")))); + EXPECT_THAT(style->entries[0].key.name, Eq(test::ParseNameOrDie("android:attr/bar"))); } TEST_F(ResourceParserTest, ParseStyleWithRawStringItem) { @@ -634,7 +634,7 @@ TEST_F(ResourceParserTest, ParseStyleWithInferredParent) { Style* style = test::GetValue<Style>(&table_, "style/foo.bar"); ASSERT_THAT(style, NotNull()); ASSERT_TRUE(style->parent); - EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("style/foo")))); + EXPECT_THAT(style->parent.value().name, Eq(test::ParseNameOrDie("style/foo"))); EXPECT_TRUE(style->parent_inferred); } @@ -672,7 +672,7 @@ TEST_F(ResourceParserTest, ParseAttributesDeclareStyleable) { </declare-styleable>)"; ASSERT_TRUE(TestParse(input)); - Maybe<ResourceTable::SearchResult> result = + std::optional<ResourceTable::SearchResult> result = table_.FindResource(test::ParseNameOrDie("styleable/foo")); ASSERT_TRUE(result); EXPECT_THAT(result.value().entry->visibility.level, Eq(Visibility::Level::kPublic)); @@ -695,9 +695,9 @@ TEST_F(ResourceParserTest, ParseAttributesDeclareStyleable) { ASSERT_THAT(styleable, NotNull()); ASSERT_THAT(styleable->entries, SizeIs(3)); - EXPECT_THAT(styleable->entries[0].name, Eq(make_value(test::ParseNameOrDie("attr/bar")))); - EXPECT_THAT(styleable->entries[1].name, Eq(make_value(test::ParseNameOrDie("attr/bat")))); - EXPECT_THAT(styleable->entries[2].name, Eq(make_value(test::ParseNameOrDie("attr/baz")))); + EXPECT_THAT(styleable->entries[0].name, Eq(test::ParseNameOrDie("attr/bar"))); + EXPECT_THAT(styleable->entries[1].name, Eq(test::ParseNameOrDie("attr/bat"))); + EXPECT_THAT(styleable->entries[2].name, Eq(test::ParseNameOrDie("attr/baz"))); } TEST_F(ResourceParserTest, ParseDeclareStyleablePreservingVisibility) { @@ -913,7 +913,8 @@ TEST_F(ResourceParserTest, AutoIncrementIdsInPublicGroup) { </public-group>)"; ASSERT_TRUE(TestParse(input)); - Maybe<ResourceTable::SearchResult> result = table_.FindResource(test::ParseNameOrDie("attr/foo")); + std::optional<ResourceTable::SearchResult> result = + table_.FindResource(test::ParseNameOrDie("attr/foo")); ASSERT_TRUE(result); ASSERT_TRUE(result.value().entry->id); EXPECT_THAT(result.value().entry->id.value(), Eq(ResourceId(0x01010040))); @@ -932,7 +933,8 @@ TEST_F(ResourceParserTest, StagingPublicGroup) { </staging-public-group>)"; ASSERT_TRUE(TestParse(input)); - Maybe<ResourceTable::SearchResult> result = table_.FindResource(test::ParseNameOrDie("attr/foo")); + std::optional<ResourceTable::SearchResult> result = + table_.FindResource(test::ParseNameOrDie("attr/foo")); ASSERT_TRUE(result); ASSERT_TRUE(result.value().entry->id); @@ -959,7 +961,7 @@ TEST_F(ResourceParserTest, StrongestSymbolVisibilityWins) { <java-symbol type="string" name="foo" />)"; ASSERT_TRUE(TestParse(input)); - Maybe<ResourceTable::SearchResult> result = + std::optional<ResourceTable::SearchResult> result = table_.FindResource(test::ParseNameOrDie("string/foo")); ASSERT_TRUE(result); @@ -977,7 +979,7 @@ TEST_F(ResourceParserTest, ExternalTypesShouldOnlyBeReferences) { TEST_F(ResourceParserTest, AddResourcesElementShouldAddEntryWithUndefinedSymbol) { ASSERT_TRUE(TestParse(R"(<add-resource name="bar" type="string" />)")); - Maybe<ResourceTable::SearchResult> result = + std::optional<ResourceTable::SearchResult> result = table_.FindResource(test::ParseNameOrDie("string/bar")); ASSERT_TRUE(result); const ResourceEntry* entry = result.value().entry; diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp index 8ab1493c6ab3..ad014a23be87 100644 --- a/tools/aapt2/ResourceTable.cpp +++ b/tools/aapt2/ResourceTable.cpp @@ -18,6 +18,7 @@ #include <algorithm> #include <memory> +#include <optional> #include <tuple> #include "android-base/logging.h" @@ -68,7 +69,7 @@ struct NameEqualRange { template <typename T, typename U> bool less_than_struct_with_name_and_id(const T& lhs, - const std::pair<std::string_view, Maybe<U>>& rhs) { + const std::pair<std::string_view, std::optional<U>>& rhs) { if (lhs.id != rhs.second) { return lhs.id < rhs.second; } @@ -341,20 +342,20 @@ struct EntryViewComparer { void InsertEntryIntoTableView(ResourceTableView& table, const ResourceTablePackage* package, const ResourceTableType* type, const std::string& entry_name, - const Maybe<ResourceId>& id, const Visibility& visibility, - const Maybe<AllowNew>& allow_new, - const Maybe<OverlayableItem>& overlayable_item, - const Maybe<StagedId>& staged_id, + const std::optional<ResourceId>& id, const Visibility& visibility, + const std::optional<AllowNew>& allow_new, + const std::optional<OverlayableItem>& overlayable_item, + const std::optional<StagedId>& staged_id, const std::vector<std::unique_ptr<ResourceConfigValue>>& values) { SortedVectorInserter<ResourceTablePackageView, PackageViewComparer> package_inserter; SortedVectorInserter<ResourceTableTypeView, TypeViewComparer> type_inserter; SortedVectorInserter<ResourceTableEntryView, EntryViewComparer> entry_inserter; ResourceTablePackageView new_package{package->name, - id ? id.value().package_id() : Maybe<uint8_t>{}}; + id ? id.value().package_id() : std::optional<uint8_t>{}}; auto view_package = package_inserter.Insert(table.packages, std::move(new_package)); - ResourceTableTypeView new_type{type->type, id ? id.value().type_id() : Maybe<uint8_t>{}}; + ResourceTableTypeView new_type{type->type, id ? id.value().type_id() : std::optional<uint8_t>{}}; auto view_type = type_inserter.Insert(view_package->types, std::move(new_type)); if (visibility.level == Visibility::Level::kPublic) { @@ -363,7 +364,7 @@ void InsertEntryIntoTableView(ResourceTableView& table, const ResourceTablePacka } ResourceTableEntryView new_entry{.name = entry_name, - .id = id ? id.value().entry_id() : Maybe<uint16_t>{}, + .id = id ? id.value().entry_id() : std::optional<uint16_t>{}, .visibility = visibility, .allow_new = allow_new, .overlayable_item = overlayable_item, @@ -585,7 +586,8 @@ bool ResourceTable::AddResource(NewResource&& res, IDiagnostics* diag) { return true; } -Maybe<ResourceTable::SearchResult> ResourceTable::FindResource(const ResourceNameRef& name) const { +std::optional<ResourceTable::SearchResult> ResourceTable::FindResource( + const ResourceNameRef& name) const { ResourceTablePackage* package = FindPackage(name.package); if (package == nullptr) { return {}; @@ -603,8 +605,8 @@ Maybe<ResourceTable::SearchResult> ResourceTable::FindResource(const ResourceNam return SearchResult{package, type, entry}; } -Maybe<ResourceTable::SearchResult> ResourceTable::FindResource(const ResourceNameRef& name, - ResourceId id) const { +std::optional<ResourceTable::SearchResult> ResourceTable::FindResource(const ResourceNameRef& name, + ResourceId id) const { ResourceTablePackage* package = FindPackage(name.package); if (package == nullptr) { return {}; diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h index bae1d827a841..2e17659b0679 100644 --- a/tools/aapt2/ResourceTable.h +++ b/tools/aapt2/ResourceTable.h @@ -120,18 +120,18 @@ class ResourceEntry { const std::string name; // The entry ID for this resource (the EEEE in 0xPPTTEEEE). - Maybe<ResourceId> id; + std::optional<ResourceId> id; // Whether this resource is public (and must maintain the same entry ID across builds). Visibility visibility; - Maybe<AllowNew> allow_new; + std::optional<AllowNew> allow_new; // The declarations of this resource as overlayable for RROs - Maybe<OverlayableItem> overlayable_item; + std::optional<OverlayableItem> overlayable_item; // The staged resource id for a finalized resource. - Maybe<StagedId> staged_id; + std::optional<StagedId> staged_id; // The resource's values for each configuration. std::vector<std::unique_ptr<ResourceConfigValue>> values; @@ -205,11 +205,11 @@ class ResourceTablePackage { struct ResourceTableEntryView { std::string name; - Maybe<uint16_t> id; + std::optional<uint16_t> id; Visibility visibility; - Maybe<AllowNew> allow_new; - Maybe<OverlayableItem> overlayable_item; - Maybe<StagedId> staged_id; + std::optional<AllowNew> allow_new; + std::optional<OverlayableItem> overlayable_item; + std::optional<StagedId> staged_id; std::vector<const ResourceConfigValue*> values; const ResourceConfigValue* FindValue(const android::ConfigDescription& config, @@ -218,7 +218,7 @@ struct ResourceTableEntryView { struct ResourceTableTypeView { ResourceType type; - Maybe<uint8_t> id; + std::optional<uint8_t> id; Visibility::Level visibility_level = Visibility::Level::kUndefined; // Entries sorted in ascending entry id order. If ids have not been assigned, the entries are @@ -228,7 +228,7 @@ struct ResourceTableTypeView { struct ResourceTablePackageView { std::string name; - Maybe<uint8_t> id; + std::optional<uint8_t> id; // Types sorted in ascending type id order. If ids have not been assigned, the types are sorted by // their declaration order in the ResourceType enum. std::vector<ResourceTableTypeView> types; @@ -309,8 +309,8 @@ class ResourceTable { ResourceEntry* entry; }; - Maybe<SearchResult> FindResource(const ResourceNameRef& name) const; - Maybe<SearchResult> FindResource(const ResourceNameRef& name, ResourceId id) const; + std::optional<SearchResult> FindResource(const ResourceNameRef& name) const; + std::optional<SearchResult> FindResource(const ResourceNameRef& name, ResourceId id) const; bool RemoveResource(const ResourceNameRef& name, ResourceId id) const; // Returns the package struct with the given name, or nullptr if such a package does not diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp index 38391c99f55a..de73d2c203e4 100644 --- a/tools/aapt2/ResourceTable_test.cpp +++ b/tools/aapt2/ResourceTable_test.cpp @@ -162,7 +162,7 @@ TEST(ResourceTableTest, ProductVaryingValues) { EXPECT_THAT(test::GetValueForConfigAndProduct<Id>(&table, "android:string/foo",test::ParseConfigOrDie("land"), "tablet"), NotNull()); EXPECT_THAT(test::GetValueForConfigAndProduct<Id>(&table, "android:string/foo",test::ParseConfigOrDie("land"), "phone"), NotNull()); - Maybe<ResourceTable::SearchResult> sr = + std::optional<ResourceTable::SearchResult> sr = table.FindResource(test::ParseNameOrDie("android:string/foo")); ASSERT_TRUE(sr); std::vector<ResourceConfigValue*> values = @@ -187,7 +187,7 @@ static ::testing::AssertionResult VisibilityOfResource(const ResourceTable& tabl const ResourceNameRef& name, Visibility::Level level, const StringPiece& comment) { - Maybe<ResourceTable::SearchResult> result = table.FindResource(name); + std::optional<ResourceTable::SearchResult> result = table.FindResource(name); if (!result) { return ::testing::AssertionFailure() << "no resource '" << name << "' found in table"; } @@ -242,7 +242,7 @@ TEST(ResourceTableTest, SetAllowNew) { const ResourceName name = test::ParseNameOrDie("android:string/foo"); AllowNew allow_new; - Maybe<ResourceTable::SearchResult> result; + std::optional<ResourceTable::SearchResult> result; allow_new.comment = "first"; ASSERT_TRUE(table.AddResource(NewResourceBuilder(name).SetAllowNew(allow_new).Build(), @@ -274,7 +274,7 @@ TEST(ResourceTableTest, SetOverlayable) { const ResourceName name = test::ParseNameOrDie("android:string/foo"); ASSERT_TRUE(table.AddResource(NewResourceBuilder(name).SetOverlayable(overlayable_item).Build(), test::GetDiagnostics())); - Maybe<ResourceTable::SearchResult> search_result = table.FindResource(name); + std::optional<ResourceTable::SearchResult> search_result = table.FindResource(name); ASSERT_TRUE(search_result); ASSERT_TRUE(search_result.value().entry->overlayable_item); diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp index e0e80ac02dea..ead06bf989d5 100644 --- a/tools/aapt2/ResourceUtils.cpp +++ b/tools/aapt2/ResourceUtils.cpp @@ -40,8 +40,7 @@ using ::android::base::StringPrintf; namespace aapt { namespace ResourceUtils { -Maybe<ResourceName> ToResourceName( - const android::ResTable::resource_name& name_in) { +std::optional<ResourceName> ToResourceName(const android::ResTable::resource_name& name_in) { // TODO: Remove this when ResTable and AssetManager(1) are removed from AAPT2 ResourceName name_out; if (!name_in.package) { @@ -78,7 +77,7 @@ Maybe<ResourceName> ToResourceName( return name_out; } -Maybe<ResourceName> ToResourceName(const android::AssetManager2::ResourceName& name_in) { +std::optional<ResourceName> ToResourceName(const android::AssetManager2::ResourceName& name_in) { ResourceName name_out; if (!name_in.package) { return {}; @@ -251,8 +250,7 @@ bool IsAttributeReference(const StringPiece& str) { * <[*]package>:[style/]<entry> * [[*]package:style/]<entry> */ -Maybe<Reference> ParseStyleParentReference(const StringPiece& str, - std::string* out_error) { +std::optional<Reference> ParseStyleParentReference(const StringPiece& str, std::string* out_error) { if (str.empty()) { return {}; } @@ -301,7 +299,7 @@ Maybe<Reference> ParseStyleParentReference(const StringPiece& str, return result; } -Maybe<Reference> ParseXmlAttributeName(const StringPiece& str) { +std::optional<Reference> ParseXmlAttributeName(const StringPiece& str) { StringPiece trimmed_str = util::TrimWhitespace(str); const char* start = trimmed_str.data(); const char* const end = start + trimmed_str.size(); @@ -326,7 +324,7 @@ Maybe<Reference> ParseXmlAttributeName(const StringPiece& str) { } ref.name = ResourceName(package, ResourceType::kAttr, name.empty() ? trimmed_str : name); - return Maybe<Reference>(std::move(ref)); + return std::optional<Reference>(std::move(ref)); } std::unique_ptr<Reference> TryParseReference(const StringPiece& str, @@ -488,18 +486,18 @@ std::unique_ptr<BinaryPrimitive> TryParseColor(const StringPiece& str) { : util::make_unique<BinaryPrimitive>(value); } -Maybe<bool> ParseBool(const StringPiece& str) { +std::optional<bool> ParseBool(const StringPiece& str) { StringPiece trimmed_str(util::TrimWhitespace(str)); if (trimmed_str == "true" || trimmed_str == "TRUE" || trimmed_str == "True") { - return Maybe<bool>(true); + return std::optional<bool>(true); } else if (trimmed_str == "false" || trimmed_str == "FALSE" || trimmed_str == "False") { - return Maybe<bool>(false); + return std::optional<bool>(false); } return {}; } -Maybe<uint32_t> ParseInt(const StringPiece& str) { +std::optional<uint32_t> ParseInt(const StringPiece& str) { std::u16string str16 = util::Utf8ToUtf16(str); android::Res_value value; if (android::ResTable::stringToInt(str16.data(), str16.size(), &value)) { @@ -508,7 +506,7 @@ Maybe<uint32_t> ParseInt(const StringPiece& str) { return {}; } -Maybe<ResourceId> ParseResourceId(const StringPiece& str) { +std::optional<ResourceId> ParseResourceId(const StringPiece& str) { StringPiece trimmed_str(util::TrimWhitespace(str)); std::u16string str16 = util::Utf8ToUtf16(trimmed_str); @@ -524,7 +522,7 @@ Maybe<ResourceId> ParseResourceId(const StringPiece& str) { return {}; } -Maybe<int> ParseSdkVersion(const StringPiece& str) { +std::optional<int> ParseSdkVersion(const StringPiece& str) { StringPiece trimmed_str(util::TrimWhitespace(str)); std::u16string str16 = util::Utf8ToUtf16(trimmed_str); @@ -534,7 +532,7 @@ Maybe<int> ParseSdkVersion(const StringPiece& str) { } // Try parsing the code name. - Maybe<int> entry = GetDevelopmentSdkCodeNameVersion(trimmed_str); + std::optional<int> entry = GetDevelopmentSdkCodeNameVersion(trimmed_str); if (entry) { return entry.value(); } @@ -551,7 +549,7 @@ Maybe<int> ParseSdkVersion(const StringPiece& str) { } std::unique_ptr<BinaryPrimitive> TryParseBool(const StringPiece& str) { - if (Maybe<bool> maybe_result = ParseBool(str)) { + if (std::optional<bool> maybe_result = ParseBool(str)) { const uint32_t data = maybe_result.value() ? 0xffffffffu : 0u; return util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_INT_BOOLEAN, data); } diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h index be493db8cee0..fe450a834dfa 100644 --- a/tools/aapt2/ResourceUtils.h +++ b/tools/aapt2/ResourceUtils.h @@ -75,35 +75,33 @@ bool IsAttributeReference(const android::StringPiece& str); /** * Convert an android::ResTable::resource_name to an aapt::ResourceName struct. */ -Maybe<ResourceName> ToResourceName( - const android::ResTable::resource_name& name); +std::optional<ResourceName> ToResourceName(const android::ResTable::resource_name& name); /** * Convert an android::AssetManager2::ResourceName to an aapt::ResourceName struct. */ -Maybe<ResourceName> ToResourceName( - const android::AssetManager2::ResourceName& name_in); +std::optional<ResourceName> ToResourceName(const android::AssetManager2::ResourceName& name_in); /** * Returns a boolean value if the string is equal to TRUE, true, True, FALSE, * false, or False. */ -Maybe<bool> ParseBool(const android::StringPiece& str); +std::optional<bool> ParseBool(const android::StringPiece& str); /** * Returns a uint32_t if the string is an integer. */ -Maybe<uint32_t> ParseInt(const android::StringPiece& str); +std::optional<uint32_t> ParseInt(const android::StringPiece& str); /** * Returns an ID if it the string represented a valid ID. */ -Maybe<ResourceId> ParseResourceId(const android::StringPiece& str); +std::optional<ResourceId> ParseResourceId(const android::StringPiece& str); /** * Parses an SDK version, which can be an integer, or a letter from A-Z. */ -Maybe<int> ParseSdkVersion(const android::StringPiece& str); +std::optional<int> ParseSdkVersion(const android::StringPiece& str); /* * Returns a Reference, or None Maybe instance if the string `str` was parsed as @@ -116,7 +114,8 @@ Maybe<int> ParseSdkVersion(const android::StringPiece& str); * ?[package:]style/<entry> or * <package>:[style/]<entry> */ -Maybe<Reference> ParseStyleParentReference(const android::StringPiece& str, std::string* out_error); +std::optional<Reference> ParseStyleParentReference(const android::StringPiece& str, + std::string* out_error); /* * Returns a Reference if the string `str` was parsed as a valid XML attribute @@ -125,7 +124,7 @@ Maybe<Reference> ParseStyleParentReference(const android::StringPiece& str, std: * * package:entry */ -Maybe<Reference> ParseXmlAttributeName(const android::StringPiece& str); +std::optional<Reference> ParseXmlAttributeName(const android::StringPiece& str); /* * Returns a Reference object if the string was parsed as a resource or diff --git a/tools/aapt2/ResourceUtils_test.cpp b/tools/aapt2/ResourceUtils_test.cpp index b08bf9a1ff17..1aaa34deee79 100644 --- a/tools/aapt2/ResourceUtils_test.cpp +++ b/tools/aapt2/ResourceUtils_test.cpp @@ -30,15 +30,15 @@ using ::testing::Pointee; namespace aapt { TEST(ResourceUtilsTest, ParseBool) { - EXPECT_THAT(ResourceUtils::ParseBool("true"), Eq(Maybe<bool>(true))); - EXPECT_THAT(ResourceUtils::ParseBool("TRUE"), Eq(Maybe<bool>(true))); - EXPECT_THAT(ResourceUtils::ParseBool("True"), Eq(Maybe<bool>(true))); + EXPECT_THAT(ResourceUtils::ParseBool("true"), Eq(std::optional<bool>(true))); + EXPECT_THAT(ResourceUtils::ParseBool("TRUE"), Eq(std::optional<bool>(true))); + EXPECT_THAT(ResourceUtils::ParseBool("True"), Eq(std::optional<bool>(true))); - EXPECT_THAT(ResourceUtils::ParseBool("false"), Eq(Maybe<bool>(false))); - EXPECT_THAT(ResourceUtils::ParseBool("FALSE"), Eq(Maybe<bool>(false))); - EXPECT_THAT(ResourceUtils::ParseBool("False"), Eq(Maybe<bool>(false))); + EXPECT_THAT(ResourceUtils::ParseBool("false"), Eq(std::optional<bool>(false))); + EXPECT_THAT(ResourceUtils::ParseBool("FALSE"), Eq(std::optional<bool>(false))); + EXPECT_THAT(ResourceUtils::ParseBool("False"), Eq(std::optional<bool>(false))); - EXPECT_THAT(ResourceUtils::ParseBool(" False\n "), Eq(Maybe<bool>(false))); + EXPECT_THAT(ResourceUtils::ParseBool(" False\n "), Eq(std::optional<bool>(false))); } TEST(ResourceUtilsTest, ParseResourceName) { @@ -155,41 +155,42 @@ TEST(ResourceUtilsTest, ParseStyleParentReference) { const ResourceName kStyleFooName({}, ResourceType::kStyle, "foo"); std::string err_str; - Maybe<Reference> ref = ResourceUtils::ParseStyleParentReference("@android:style/foo", &err_str); + std::optional<Reference> ref = + ResourceUtils::ParseStyleParentReference("@android:style/foo", &err_str); ASSERT_TRUE(ref); - EXPECT_THAT(ref.value().name, Eq(make_value(kAndroidStyleFooName))); + EXPECT_THAT(ref.value().name, Eq(kAndroidStyleFooName)); ref = ResourceUtils::ParseStyleParentReference("@style/foo", &err_str); ASSERT_TRUE(ref); - EXPECT_THAT(ref.value().name, Eq(make_value(kStyleFooName))); + EXPECT_THAT(ref.value().name, Eq(kStyleFooName)); ref = ResourceUtils::ParseStyleParentReference("?android:style/foo", &err_str); ASSERT_TRUE(ref); - EXPECT_THAT(ref.value().name, Eq(make_value(kAndroidStyleFooName))); + EXPECT_THAT(ref.value().name, Eq(kAndroidStyleFooName)); ref = ResourceUtils::ParseStyleParentReference("?style/foo", &err_str); ASSERT_TRUE(ref); - EXPECT_THAT(ref.value().name, Eq(make_value(kStyleFooName))); + EXPECT_THAT(ref.value().name, Eq(kStyleFooName)); ref = ResourceUtils::ParseStyleParentReference("android:style/foo", &err_str); ASSERT_TRUE(ref); - EXPECT_THAT(ref.value().name, Eq(make_value(kAndroidStyleFooName))); + EXPECT_THAT(ref.value().name, Eq(kAndroidStyleFooName)); ref = ResourceUtils::ParseStyleParentReference("android:foo", &err_str); ASSERT_TRUE(ref); - EXPECT_THAT(ref.value().name, Eq(make_value(kAndroidStyleFooName))); + EXPECT_THAT(ref.value().name, Eq(kAndroidStyleFooName)); ref = ResourceUtils::ParseStyleParentReference("@android:foo", &err_str); ASSERT_TRUE(ref); - EXPECT_THAT(ref.value().name, Eq(make_value(kAndroidStyleFooName))); + EXPECT_THAT(ref.value().name, Eq(kAndroidStyleFooName)); ref = ResourceUtils::ParseStyleParentReference("foo", &err_str); ASSERT_TRUE(ref); - EXPECT_THAT(ref.value().name, Eq(make_value(kStyleFooName))); + EXPECT_THAT(ref.value().name, Eq(kStyleFooName)); ref = ResourceUtils::ParseStyleParentReference("*android:style/foo", &err_str); ASSERT_TRUE(ref); - EXPECT_THAT(ref.value().name, Eq(make_value(kAndroidStyleFooName))); + EXPECT_THAT(ref.value().name, Eq(kAndroidStyleFooName)); EXPECT_TRUE(ref.value().private_reference); } @@ -228,15 +229,11 @@ TEST(ResourceUtilsTest, ItemsWithWhitespaceAreParsedCorrectly) { } TEST(ResourceUtilsTest, ParseSdkVersionWithCodename) { - EXPECT_THAT(ResourceUtils::ParseSdkVersion("Q"), Eq(Maybe<int>(10000))); - EXPECT_THAT( - ResourceUtils::ParseSdkVersion("Q.fingerprint"), - Eq(Maybe<int>(10000))); - - EXPECT_THAT(ResourceUtils::ParseSdkVersion("R"), Eq(Maybe<int>(10000))); - EXPECT_THAT( - ResourceUtils::ParseSdkVersion("R.fingerprint"), - Eq(Maybe<int>(10000))); + EXPECT_THAT(ResourceUtils::ParseSdkVersion("Q"), Eq(std::optional<int>(10000))); + EXPECT_THAT(ResourceUtils::ParseSdkVersion("Q.fingerprint"), Eq(std::optional<int>(10000))); + + EXPECT_THAT(ResourceUtils::ParseSdkVersion("R"), Eq(std::optional<int>(10000))); + EXPECT_THAT(ResourceUtils::ParseSdkVersion("R.fingerprint"), Eq(std::optional<int>(10000))); } TEST(ResourceUtilsTest, StringBuilderWhitespaceRemoval) { diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp index 2a90f267f185..b3ab4ffc649b 100644 --- a/tools/aapt2/ResourceValues.cpp +++ b/tools/aapt2/ResourceValues.cpp @@ -120,7 +120,7 @@ bool Reference::Flatten(android::Res_value* out_value) const { return false; } - const ResourceId resid = id.value_or_default(ResourceId(0)); + const ResourceId resid = id.value_or(ResourceId(0)); const bool dynamic = resid.is_valid() && is_dynamic; if (reference_type == Reference::Type::kResource) { @@ -1040,7 +1040,7 @@ void Macro::Print(std::ostream* out) const { } bool operator<(const Reference& a, const Reference& b) { - int cmp = a.name.value_or_default({}).compare(b.name.value_or_default({})); + int cmp = a.name.value_or(ResourceName{}).compare(b.name.value_or(ResourceName{})); if (cmp != 0) return cmp < 0; return a.id < b.id; } diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h index d903b7e1b8b3..1694d6b6fe4a 100644 --- a/tools/aapt2/ResourceValues.h +++ b/tools/aapt2/ResourceValues.h @@ -31,7 +31,6 @@ #include "ValueTransformer.h" #include "io/File.h" #include "text/Printer.h" -#include "util/Maybe.h" namespace aapt { @@ -159,8 +158,8 @@ struct Reference : public TransformableItem<Reference, BaseItem<Reference>> { kAttribute, }; - Maybe<ResourceName> name; - Maybe<ResourceId> id; + std::optional<ResourceName> name; + std::optional<ResourceId> id; std::optional<uint32_t> type_flags; Reference::Type reference_type; bool private_reference = false; @@ -327,7 +326,7 @@ struct Style : public TransformableValue<Style, BaseValue<Style>> { friend std::ostream& operator<<(std::ostream& out, const Entry& entry); }; - Maybe<Reference> parent; + std::optional<Reference> parent; // If set to true, the parent was auto inferred from the style's name. bool parent_inferred = false; diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp index ebe41da5a03e..f7a5ba1f161d 100644 --- a/tools/aapt2/SdkConstants.cpp +++ b/tools/aapt2/SdkConstants.cpp @@ -77,9 +77,10 @@ ApiVersion FindAttributeSdkLevel(const ResourceId& id) { return iter->second; } -Maybe<ApiVersion> GetDevelopmentSdkCodeNameVersion(const StringPiece& code_name) { +std::optional<ApiVersion> GetDevelopmentSdkCodeNameVersion(const StringPiece& code_name) { return (sDevelopmentSdkCodeNames.find(code_name) == sDevelopmentSdkCodeNames.end()) - ? Maybe<ApiVersion>() : sDevelopmentSdkLevel; + ? std::optional<ApiVersion>() + : sDevelopmentSdkLevel; } } // namespace aapt diff --git a/tools/aapt2/SdkConstants.h b/tools/aapt2/SdkConstants.h index 6bb6ddb13bdb..7518e707d22c 100644 --- a/tools/aapt2/SdkConstants.h +++ b/tools/aapt2/SdkConstants.h @@ -60,7 +60,7 @@ enum : ApiVersion { }; ApiVersion FindAttributeSdkLevel(const ResourceId& id); -Maybe<ApiVersion> GetDevelopmentSdkCodeNameVersion(const android::StringPiece& code_name); +std::optional<ApiVersion> GetDevelopmentSdkCodeNameVersion(const android::StringPiece& code_name); } // namespace aapt diff --git a/tools/aapt2/Source.h b/tools/aapt2/Source.h index 92934c343960..4f9369a5d517 100644 --- a/tools/aapt2/Source.h +++ b/tools/aapt2/Source.h @@ -17,21 +17,20 @@ #ifndef AAPT_SOURCE_H #define AAPT_SOURCE_H +#include <optional> #include <ostream> #include <string> #include "android-base/stringprintf.h" #include "androidfw/StringPiece.h" -#include "util/Maybe.h" - namespace aapt { // Represents a file on disk. Used for logging and showing errors. struct Source { std::string path; - Maybe<size_t> line; - Maybe<std::string> archive; + std::optional<size_t> line; + std::optional<std::string> archive; Source() = default; diff --git a/tools/aapt2/cmd/Command.cpp b/tools/aapt2/cmd/Command.cpp index 919b4c98fa8f..b1452fad0e8f 100644 --- a/tools/aapt2/cmd/Command.cpp +++ b/tools/aapt2/cmd/Command.cpp @@ -72,7 +72,7 @@ void Command::AddRequiredFlagList(const StringPiece& name, const StringPiece& de } void Command::AddOptionalFlag(const StringPiece& name, const StringPiece& description, - Maybe<std::string>* value, uint32_t flags) { + std::optional<std::string>* value, uint32_t flags) { auto func = [value, flags](const StringPiece& arg) -> bool { *value = (flags & Command::kPath) ? GetSafePath(arg) : arg.to_string(); return true; diff --git a/tools/aapt2/cmd/Command.h b/tools/aapt2/cmd/Command.h index d21571d530d2..8678cda59856 100644 --- a/tools/aapt2/cmd/Command.h +++ b/tools/aapt2/cmd/Command.h @@ -18,6 +18,7 @@ #define AAPT_COMMAND_H #include <functional> +#include <optional> #include <ostream> #include <string> #include <unordered_set> @@ -25,19 +26,20 @@ #include "androidfw/StringPiece.h" -#include "util/Maybe.h" - namespace aapt { class Command { public: - explicit Command(const android::StringPiece& name) : name_(name.to_string()), - short_name_(""), - full_subcommand_name_(name.to_string()) {} + explicit Command(const android::StringPiece& name) + : name_(name.to_string()), full_subcommand_name_(name.to_string()){}; explicit Command(const android::StringPiece& name, const android::StringPiece& short_name) - : name_(name.to_string()), short_name_(short_name.to_string()), - full_subcommand_name_(name.to_string()) {} + : name_(name.to_string()), + short_name_(short_name.to_string()), + full_subcommand_name_(name.to_string()){}; + + Command(Command&&) = default; + Command& operator=(Command&&) = default; virtual ~Command() = default; @@ -58,7 +60,7 @@ class Command { uint32_t flags = 0); void AddOptionalFlag(const android::StringPiece& name, const android::StringPiece& description, - Maybe<std::string>* value, uint32_t flags = 0); + std::optional<std::string>* value, uint32_t flags = 0); void AddOptionalFlagList(const android::StringPiece& name, const android::StringPiece& description, std::vector<std::string>* value, @@ -87,8 +89,6 @@ class Command { virtual int Action(const std::vector<std::string>& args) = 0; private: - DISALLOW_COPY_AND_ASSIGN(Command); - struct Flag { explicit Flag(const android::StringPiece& name, const android::StringPiece& description, const bool is_required, const size_t num_args, @@ -104,8 +104,8 @@ class Command { bool found = false; }; - const std::string name_; - const std::string short_name_; + std::string name_; + std::string short_name_; std::string description_ = ""; std::string full_subcommand_name_; diff --git a/tools/aapt2/cmd/Command_test.cpp b/tools/aapt2/cmd/Command_test.cpp index 65608fdf64a7..7aa1aa017f7b 100644 --- a/tools/aapt2/cmd/Command_test.cpp +++ b/tools/aapt2/cmd/Command_test.cpp @@ -38,7 +38,7 @@ TEST(CommandTest, LongFullyQualifiedPathWindows) { TestCommand command; std::string required_flag; command.AddRequiredFlag("--rflag", "", &required_flag, Command::kPath); - Maybe<std::string> optional_flag; + std::optional<std::string> optional_flag; command.AddOptionalFlag("--oflag", "", &optional_flag, Command::kPath); std::vector<std::string> required_flag_list; command.AddRequiredFlagList("--rlflag", "", &required_flag_list, Command::kPath); diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp index cd5015e81203..fe560180bd48 100644 --- a/tools/aapt2/cmd/Compile.cpp +++ b/tools/aapt2/cmd/Compile.cpp @@ -47,7 +47,6 @@ #include "io/ZipArchive.h" #include "trace/TraceBuffer.h" #include "util/Files.h" -#include "util/Maybe.h" #include "util/Util.h" #include "xml/XmlDom.h" #include "xml/XmlPullParser.h" @@ -75,10 +74,10 @@ struct ResourcePathData { }; // Resource file paths are expected to look like: [--/res/]type[-config]/name -static Maybe<ResourcePathData> ExtractResourcePathData(const std::string& path, - const char dir_sep, - std::string* out_error, - const CompileOptions& options) { +static std::optional<ResourcePathData> ExtractResourcePathData(const std::string& path, + const char dir_sep, + std::string* out_error, + const CompileOptions& options) { std::vector<std::string> parts = util::Split(path, dir_sep); if (parts.size() < 2) { if (out_error) *out_error = "bad resource path"; @@ -337,7 +336,7 @@ static bool IsValidFile(IAaptContext* context, const std::string& input_path) { if (file_type == file::FileType::kDirectory) { context->GetDiagnostics()->Error(DiagMessage(input_path) << "resource file cannot be a directory"); - } else if (file_type == file::FileType::kNonexistant) { + } else if (file_type == file::FileType::kNonExistant) { context->GetDiagnostics()->Error(DiagMessage(input_path) << "file not found"); } else { context->GetDiagnostics()->Error(DiagMessage(input_path) diff --git a/tools/aapt2/cmd/Compile.h b/tools/aapt2/cmd/Compile.h index 1bc1f6651f85..bd2e3d72a551 100644 --- a/tools/aapt2/cmd/Compile.h +++ b/tools/aapt2/cmd/Compile.h @@ -17,7 +17,10 @@ #ifndef AAPT2_COMPILE_H #define AAPT2_COMPILE_H -#include "androidfw/StringPiece.h" +#include <optional> + +#include <androidfw/StringPiece.h> + #include "format/Archive.h" #include "process/IResourceTableConsumer.h" #include "Command.h" @@ -28,11 +31,11 @@ namespace aapt { struct CompileOptions { std::string output_path; - Maybe<std::string> source_path; - Maybe<std::string> res_dir; - Maybe<std::string> res_zip; - Maybe<std::string> generate_text_symbols_path; - Maybe<Visibility::Level> visibility; + std::optional<std::string> source_path; + std::optional<std::string> res_dir; + std::optional<std::string> res_zip; + std::optional<std::string> generate_text_symbols_path; + std::optional<Visibility::Level> visibility; bool pseudolocalize = false; bool no_png_crunch = false; bool legacy_mode = false; @@ -80,8 +83,8 @@ class CompileCommand : public Command { private: IDiagnostics* diagnostic_; CompileOptions options_; - Maybe<std::string> visibility_; - Maybe<std::string> trace_folder_; + std::optional<std::string> visibility_; + std::optional<std::string> trace_folder_; }; int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter* output_writer, diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp index 22bcd8589ce9..3b097e09e09d 100644 --- a/tools/aapt2/cmd/Convert.cpp +++ b/tools/aapt2/cmd/Convert.cpp @@ -367,8 +367,7 @@ int ConvertCommand::Action(const std::vector<std::string>& args) { return 1; } - Maybe<AppInfo> app_info = ExtractAppInfoFromBinaryManifest(*apk->GetManifest(), - context.GetDiagnostics()); + auto app_info = ExtractAppInfoFromBinaryManifest(*apk->GetManifest(), context.GetDiagnostics()); if (!app_info) { return 1; } diff --git a/tools/aapt2/cmd/Convert.h b/tools/aapt2/cmd/Convert.h index 7e2029dfc4d2..2cdb0c87310f 100644 --- a/tools/aapt2/cmd/Convert.h +++ b/tools/aapt2/cmd/Convert.h @@ -17,6 +17,8 @@ #ifndef AAPT2_CONVERT_H #define AAPT2_CONVERT_H +#include <optional> + #include "Command.h" #include "LoadedApk.h" #include "format/binary/TableFlattener.h" @@ -52,7 +54,7 @@ class ConvertCommand : public Command { TableFlattenerOptions table_flattener_options_; XmlFlattenerOptions xml_flattener_options_; std::string output_path_; - Maybe<std::string> output_format_; + std::optional<std::string> output_format_; bool verbose_ = false; }; diff --git a/tools/aapt2/cmd/Diff.cpp b/tools/aapt2/cmd/Diff.cpp index 3950f337b575..d9e8c921dbc5 100644 --- a/tools/aapt2/cmd/Diff.cpp +++ b/tools/aapt2/cmd/Diff.cpp @@ -87,8 +87,8 @@ static bool IsSymbolVisibilityDifferent(const Visibility& vis_a, const Visibilit } template <typename Id> -static bool IsIdDiff(const Visibility::Level& level_a, const Maybe<Id>& id_a, - const Visibility::Level& level_b, const Maybe<Id>& id_b) { +static bool IsIdDiff(const Visibility::Level& level_a, const std::optional<Id>& id_a, + const Visibility::Level& level_b, const std::optional<Id>& id_b) { if (level_a == Visibility::Level::kPublic || level_b == Visibility::Level::kPublic) { return id_a != id_b; } diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp index 3982d12f6036..0a1e021aef6b 100644 --- a/tools/aapt2/cmd/Dump.cpp +++ b/tools/aapt2/cmd/Dump.cpp @@ -257,12 +257,11 @@ int DumpConfigsCommand::Dump(LoadedApk* apk) { } int DumpPackageNameCommand::Dump(LoadedApk* apk) { - Maybe<std::string> package_name = GetPackageName(apk); - if (!package_name) { + auto package_name = GetPackageName(apk); + if (!package_name.has_value()) { return 1; } - - GetPrinter()->Println(package_name.value()); + GetPrinter()->Println(*package_name); return 0; } @@ -283,12 +282,12 @@ int DumpStringsCommand::Dump(LoadedApk* apk) { } int DumpStyleParentCommand::Dump(LoadedApk* apk) { - Maybe<std::string> package_name = GetPackageName(apk); - if (!package_name) { + auto package_name = GetPackageName(apk); + if (!package_name.has_value()) { return 1; } - const auto target_style = ResourceName(package_name.value(), ResourceType::kStyle, style_); + const auto target_style = ResourceName(*package_name, ResourceType::kStyle, style_); const auto table = apk->GetResourceTable(); if (!table) { @@ -296,7 +295,7 @@ int DumpStyleParentCommand::Dump(LoadedApk* apk) { return 1; } - Maybe<ResourceTable::SearchResult> target = table->FindResource(target_style); + std::optional<ResourceTable::SearchResult> target = table->FindResource(target_style); if (!target) { GetDiagnostics()->Error( DiagMessage() << "Target style \"" << target_style.entry << "\" does not exist"); diff --git a/tools/aapt2/cmd/Dump.h b/tools/aapt2/cmd/Dump.h index cd51f7a7718c..52616faa5f06 100644 --- a/tools/aapt2/cmd/Dump.h +++ b/tools/aapt2/cmd/Dump.h @@ -43,17 +43,17 @@ class DumpApkCommand : public Command { return diag_; } - Maybe<std::string> GetPackageName(LoadedApk* apk) { + std::optional<std::string> GetPackageName(LoadedApk* apk) { xml::Element* manifest_el = apk->GetManifest()->root.get(); if (!manifest_el) { GetDiagnostics()->Error(DiagMessage() << "No AndroidManifest."); - return Maybe<std::string>(); + return {}; } xml::Attribute* attr = manifest_el->FindAttribute({}, "package"); if (!attr) { GetDiagnostics()->Error(DiagMessage() << "No package name."); - return Maybe<std::string>(); + return {}; } return attr->value; } diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index e4d0f3b6bd23..e614a753d2d2 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -299,7 +299,7 @@ struct ResourceFileFlattenerOptions { bool do_not_fail_on_missing_resources = false; OutputFormat output_format = OutputFormat::kApk; std::unordered_set<std::string> extensions_to_not_compress; - Maybe<std::regex> regex_to_not_compress; + std::optional<std::regex> regex_to_not_compress; }; // A sampling of public framework resource IDs. @@ -741,7 +741,7 @@ static bool LoadStableIdMap(IDiagnostics* diag, const std::string& path, const size_t res_id_str_len = line.size() - res_id_start_idx; StringPiece res_id_str = util::TrimWhitespace(line.substr(res_id_start_idx, res_id_str_len)); - Maybe<ResourceId> maybe_id = ResourceUtils::ParseResourceId(res_id_str); + std::optional<ResourceId> maybe_id = ResourceUtils::ParseResourceId(res_id_str); if (!maybe_id) { diag->Error(DiagMessage(Source(path, line_no)) << "invalid resource ID '" << res_id_str << "'"); @@ -793,7 +793,7 @@ class Linker { if (!options_.manifest_fixer_options.compile_sdk_version) { xml::Attribute* attr = manifest_xml->root->FindAttribute(xml::kSchemaAndroid, "versionCode"); if (attr != nullptr) { - Maybe<std::string>& compile_sdk_version = options_.manifest_fixer_options.compile_sdk_version; + auto& compile_sdk_version = options_.manifest_fixer_options.compile_sdk_version; if (BinaryPrimitive* prim = ValueCast<BinaryPrimitive>(attr->compiled_value.get())) { switch (prim->value.dataType) { case Res_value::TYPE_INT_DEC: @@ -816,7 +816,7 @@ class Linker { if (!options_.manifest_fixer_options.compile_sdk_version_codename) { xml::Attribute* attr = manifest_xml->root->FindAttribute(xml::kSchemaAndroid, "versionName"); if (attr != nullptr) { - Maybe<std::string>& compile_sdk_version_codename = + std::optional<std::string>& compile_sdk_version_codename = options_.manifest_fixer_options.compile_sdk_version_codename; if (String* str = ValueCast<String>(attr->compiled_value.get())) { compile_sdk_version_codename = *str->value; @@ -912,7 +912,7 @@ class Linker { return true; } - Maybe<AppInfo> ExtractAppInfoFromManifest(xml::XmlResource* xml_res, IDiagnostics* diag) { + std::optional<AppInfo> ExtractAppInfoFromManifest(xml::XmlResource* xml_res, IDiagnostics* diag) { TRACE_CALL(); // Make sure the first element is <manifest> with package attribute. xml::Element* manifest_el = xml::FindRootElement(xml_res->root.get()); @@ -937,7 +937,7 @@ class Linker { if (xml::Attribute* version_code_attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode")) { - Maybe<uint32_t> maybe_code = ResourceUtils::ParseInt(version_code_attr->value); + std::optional<uint32_t> maybe_code = ResourceUtils::ParseInt(version_code_attr->value); if (!maybe_code) { diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number)) << "invalid android:versionCode '" << version_code_attr->value << "'"); @@ -948,7 +948,7 @@ class Linker { if (xml::Attribute* version_code_major_attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor")) { - Maybe<uint32_t> maybe_code = ResourceUtils::ParseInt(version_code_major_attr->value); + std::optional<uint32_t> maybe_code = ResourceUtils::ParseInt(version_code_major_attr->value); if (!maybe_code) { diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number)) << "invalid android:versionCodeMajor '" @@ -960,7 +960,7 @@ class Linker { if (xml::Attribute* revision_code_attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode")) { - Maybe<uint32_t> maybe_code = ResourceUtils::ParseInt(revision_code_attr->value); + std::optional<uint32_t> maybe_code = ResourceUtils::ParseInt(revision_code_attr->value); if (!maybe_code) { diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number)) << "invalid android:revisionCode '" << revision_code_attr->value << "'"); @@ -1094,7 +1094,7 @@ class Linker { bool WriteJavaFile(ResourceTable* table, const StringPiece& package_name_to_generate, const StringPiece& out_package, const JavaClassGeneratorOptions& java_options, - const Maybe<std::string>& out_text_symbols_path = {}) { + const std::optional<std::string>& out_text_symbols_path = {}) { if (!options_.generate_java_class_path && !out_text_symbols_path) { return true; } @@ -1251,7 +1251,7 @@ class Linker { } const std::string package_utf8 = - options_.custom_java_package.value_or_default(context_->GetCompilationPackage()); + options_.custom_java_package.value_or(context_->GetCompilationPackage()); std::string out_path = options_.generate_java_class_path.value(); file::AppendPath(&out_path, file::PackageToPath(package_utf8)); @@ -1283,7 +1283,7 @@ class Linker { return true; } - bool WriteProguardFile(const Maybe<std::string>& out, const proguard::KeepSet& keep_set) { + bool WriteProguardFile(const std::optional<std::string>& out, const proguard::KeepSet& keep_set) { TRACE_CALL(); if (!out) { return true; @@ -1374,7 +1374,7 @@ class Linker { res_name.package = context_->GetCompilationPackage(); } - Maybe<ResourceName> mangled_name = context_->GetNameMangler()->MangleName(res_name); + std::optional<ResourceName> mangled_name = context_->GetNameMangler()->MangleName(res_name); if (mangled_name) { res_name = mangled_name.value(); } @@ -1550,7 +1550,7 @@ class Linker { bool CopyAssetsDirsToApk(IArchiveWriter* writer) { std::map<std::string, std::unique_ptr<io::RegularFile>> merged_assets; for (const std::string& assets_dir : options_.assets_dirs) { - Maybe<std::vector<std::string>> files = + std::optional<std::vector<std::string>> files = file::FindFiles(assets_dir, context_->GetDiagnostics(), nullptr); if (!files) { return false; @@ -1783,7 +1783,7 @@ class Linker { package_to_rewrite = table->packages.back().get(); std::string new_package_name = StringPrintf("%s.%s", package_to_rewrite->name.c_str(), - app_info_.split_name.value_or_default("feature").c_str()); + app_info_.split_name.value_or("feature").c_str()); if (context_->IsVerbose()) { context_->GetDiagnostics()->Note( @@ -1823,7 +1823,7 @@ class Linker { } // First extract the Package name without modifying it (via --rename-manifest-package). - if (Maybe<AppInfo> maybe_app_info = + if (std::optional<AppInfo> maybe_app_info = ExtractAppInfoFromManifest(manifest_xml.get(), context_->GetDiagnostics())) { const AppInfo& app_info = maybe_app_info.value(); context_->SetCompilationPackage(app_info.package); @@ -1850,14 +1850,14 @@ class Linker { return 1; } - Maybe<AppInfo> maybe_app_info = + std::optional<AppInfo> maybe_app_info = ExtractAppInfoFromManifest(manifest_xml.get(), context_->GetDiagnostics()); if (!maybe_app_info) { return 1; } app_info_ = maybe_app_info.value(); - context_->SetMinSdkVersion(app_info_.min_sdk_version.value_or_default(0)); + context_->SetMinSdkVersion(app_info_.min_sdk_version.value_or(0)); context_->SetNameManglerPolicy(NameManglerPolicy{context_->GetCompilationPackage()}); context_->SetSplitNameDependencies(app_info_.split_name_dependencies); @@ -2231,7 +2231,7 @@ class Linker { std::map<size_t, std::string> shared_libs_; // The package name of the base application, if it is included. - Maybe<std::string> included_feature_base_; + std::optional<std::string> included_feature_base_; }; int LinkCommand::Action(const std::vector<std::string>& args) { @@ -2315,7 +2315,8 @@ int LinkCommand::Action(const std::vector<std::string>& args) { return 1; } - const Maybe<uint32_t> maybe_package_id_int = ResourceUtils::ParseInt(package_id_.value()); + const std::optional<uint32_t> maybe_package_id_int = + ResourceUtils::ParseInt(package_id_.value()); if (!maybe_package_id_int) { context.GetDiagnostics()->Error(DiagMessage() << "package ID '" << package_id_.value() << "' is not a valid integer"); @@ -2360,7 +2361,7 @@ int LinkCommand::Action(const std::vector<std::string>& args) { } if (preferred_density_) { - Maybe<uint16_t> density = + std::optional<uint16_t> density = ParseTargetDensityParameter(preferred_density_.value(), context.GetDiagnostics()); if (!density) { return 1; diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h index 768b4b2c7bfd..d8c76e297ec5 100644 --- a/tools/aapt2/cmd/Link.h +++ b/tools/aapt2/cmd/Link.h @@ -45,21 +45,21 @@ struct LinkOptions { bool auto_add_overlay = false; bool override_styles_instead_of_overlaying = false; OutputFormat output_format = OutputFormat::kApk; - Maybe<std::string> rename_resources_package; + std::optional<std::string> rename_resources_package; // Java/Proguard options. - Maybe<std::string> generate_java_class_path; - Maybe<std::string> custom_java_package; + std::optional<std::string> generate_java_class_path; + std::optional<std::string> custom_java_package; std::set<std::string> extra_java_packages; - Maybe<std::string> generate_text_symbols_path; - Maybe<std::string> generate_proguard_rules_path; - Maybe<std::string> generate_main_dex_proguard_rules_path; + std::optional<std::string> generate_text_symbols_path; + std::optional<std::string> generate_proguard_rules_path; + std::optional<std::string> generate_main_dex_proguard_rules_path; bool generate_conditional_proguard_rules = false; bool generate_minimal_proguard_rules = false; bool generate_non_final_ids = false; bool no_proguard_location_reference = false; std::vector<std::string> javadoc_annotations; - Maybe<std::string> private_symbols; + std::optional<std::string> private_symbols; // Optimizations/features. bool no_auto_version = false; @@ -70,7 +70,7 @@ struct LinkOptions { bool no_xml_namespaces = false; bool do_not_compress_anything = false; std::unordered_set<std::string> extensions_to_not_compress; - Maybe<std::regex> regex_to_not_compress; + std::optional<std::regex> regex_to_not_compress; // Static lib options. bool no_static_lib_packages = false; @@ -97,7 +97,7 @@ struct LinkOptions { // Stable ID options. std::unordered_map<ResourceName, ResourceId> stable_id_map; - Maybe<std::string> resource_id_map_path; + std::optional<std::string> resource_id_map_path; // When 'true', allow reserved package IDs to be used for applications. Pre-O, the platform // treats negative resource IDs [those with a package ID of 0x80 or higher] as invalid. @@ -321,20 +321,20 @@ class LinkCommand : public Command { std::vector<std::string> overlay_arg_list_; std::vector<std::string> extra_java_packages_; - Maybe<std::string> package_id_; + std::optional<std::string> package_id_; std::vector<std::string> configs_; - Maybe<std::string> preferred_density_; - Maybe<std::string> product_list_; - Maybe<std::string> no_compress_regex; + std::optional<std::string> preferred_density_; + std::optional<std::string> product_list_; + std::optional<std::string> no_compress_regex; bool legacy_x_flag_ = false; bool require_localization_ = false; bool verbose_ = false; bool shared_lib_ = false; bool static_lib_ = false; bool proto_format_ = false; - Maybe<std::string> stable_id_file_path_; + std::optional<std::string> stable_id_file_path_; std::vector<std::string> split_args_; - Maybe<std::string> trace_folder_; + std::optional<std::string> trace_folder_; }; }// namespace aapt diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp index 5b18a3789d76..caa3e60d6af1 100644 --- a/tools/aapt2/cmd/Optimize.cpp +++ b/tools/aapt2/cmd/Optimize.cpp @@ -354,7 +354,7 @@ bool ExtractAppDataFromManifest(OptimizeContext* context, const LoadedApk* apk, return false; } - Maybe<AppInfo> app_info = ExtractAppInfoFromBinaryManifest(*manifest, context->GetDiagnostics()); + auto app_info = ExtractAppInfoFromBinaryManifest(*manifest, context->GetDiagnostics()); if (!app_info) { context->GetDiagnostics()->Error(DiagMessage() << "failed to extract data from AndroidManifest.xml"); @@ -362,7 +362,7 @@ bool ExtractAppDataFromManifest(OptimizeContext* context, const LoadedApk* apk, } out_options->app_info = std::move(app_info.value()); - context->SetMinSdkVersion(out_options->app_info.min_sdk_version.value_or_default(0)); + context->SetMinSdkVersion(out_options->app_info.min_sdk_version.value_or(0)); return true; } @@ -380,7 +380,7 @@ int OptimizeCommand::Action(const std::vector<std::string>& args) { if (config_path_) { std::string& path = config_path_.value(); - Maybe<ConfigurationParser> for_path = ConfigurationParser::ForPath(path); + std::optional<ConfigurationParser> for_path = ConfigurationParser::ForPath(path); if (for_path) { options_.apk_artifacts = for_path.value().WithDiagnostics(diag).Parse(apk_path); if (!options_.apk_artifacts) { @@ -427,7 +427,7 @@ int OptimizeCommand::Action(const std::vector<std::string>& args) { if (target_densities_) { // Parse the target screen densities. for (const StringPiece& config_str : util::Tokenize(target_densities_.value(), ',')) { - Maybe<uint16_t> target_density = ParseTargetDensityParameter(config_str, diag); + std::optional<uint16_t> target_density = ParseTargetDensityParameter(config_str, diag); if (!target_density) { return 1; } diff --git a/tools/aapt2/cmd/Optimize.h b/tools/aapt2/cmd/Optimize.h index 3afc46b04af6..ff63e8dd76d4 100644 --- a/tools/aapt2/cmd/Optimize.h +++ b/tools/aapt2/cmd/Optimize.h @@ -29,9 +29,9 @@ struct OptimizeOptions { friend class OptimizeCommand; // Path to the output APK. - Maybe<std::string> output_path; + std::optional<std::string> output_path; // Path to the output APK directory for splits. - Maybe<std::string> output_dir; + std::optional<std::string> output_dir; // Details of the app extracted from the AndroidManifest.xml AppInfo app_info; @@ -50,7 +50,7 @@ struct OptimizeOptions { TableFlattenerOptions table_flattener_options; - Maybe<std::vector<aapt::configuration::OutputArtifact>> apk_artifacts; + std::optional<std::vector<aapt::configuration::OutputArtifact>> apk_artifacts; // Set of artifacts to keep when generating multi-APK splits. If the list is empty, all artifacts // are kept and will be written as output. @@ -60,7 +60,7 @@ struct OptimizeOptions { bool shorten_resource_paths = false; // Path to the output map of original resource paths to shortened paths. - Maybe<std::string> shortened_paths_map_path; + std::optional<std::string> shortened_paths_map_path; }; class OptimizeCommand : public Command { @@ -122,9 +122,9 @@ class OptimizeCommand : public Command { bool WriteObfuscatedPathsMap(const std::map<std::string, std::string> &path_map, const std::string &file_path); - Maybe<std::string> config_path_; - Maybe<std::string> resources_config_path_; - Maybe<std::string> target_densities_; + std::optional<std::string> config_path_; + std::optional<std::string> resources_config_path_; + std::optional<std::string> target_densities_; std::vector<std::string> configs_; std::vector<std::string> split_args_; std::unordered_set<std::string> kept_artifacts_; diff --git a/tools/aapt2/cmd/Util.cpp b/tools/aapt2/cmd/Util.cpp index 7214f1a68d2c..3244fb83fa4b 100644 --- a/tools/aapt2/cmd/Util.cpp +++ b/tools/aapt2/cmd/Util.cpp @@ -21,11 +21,10 @@ #include "android-base/logging.h" #include "androidfw/ConfigDescription.h" #include "androidfw/Locale.h" - #include "ResourceUtils.h" #include "ValueVisitor.h" #include "split/TableSplitter.h" -#include "util/Maybe.h" + #include "util/Util.h" using ::android::ConfigDescription; @@ -35,7 +34,7 @@ using ::android::base::StringPrintf; namespace aapt { -Maybe<uint16_t> ParseTargetDensityParameter(const StringPiece& arg, IDiagnostics* diag) { +std::optional<uint16_t> ParseTargetDensityParameter(const StringPiece& arg, IDiagnostics* diag) { ConfigDescription preferred_density_config; if (!ConfigDescription::Parse(arg, &preferred_density_config)) { diag->Error(DiagMessage() << "invalid density '" << arg << "' for --preferred-density option"); @@ -245,8 +244,8 @@ std::unique_ptr<xml::XmlResource> GenerateSplitManifest(const AppInfo& app_info, return doc; } -static Maybe<std::string> ExtractCompiledString(const xml::Attribute& attr, - std::string* out_error) { +static std::optional<std::string> ExtractCompiledString(const xml::Attribute& attr, + std::string* out_error) { if (attr.compiled_value != nullptr) { const String* compiled_str = ValueCast<String>(attr.compiled_value.get()); if (compiled_str != nullptr) { @@ -269,7 +268,8 @@ static Maybe<std::string> ExtractCompiledString(const xml::Attribute& attr, return {}; } -static Maybe<uint32_t> ExtractCompiledInt(const xml::Attribute& attr, std::string* out_error) { +static std::optional<uint32_t> ExtractCompiledInt(const xml::Attribute& attr, + std::string* out_error) { if (attr.compiled_value != nullptr) { const BinaryPrimitive* compiled_prim = ValueCast<BinaryPrimitive>(attr.compiled_value.get()); if (compiled_prim != nullptr) { @@ -283,7 +283,7 @@ static Maybe<uint32_t> ExtractCompiledInt(const xml::Attribute& attr, std::strin } // Fallback to the plain text value if there is one. - Maybe<uint32_t> integer = ResourceUtils::ParseInt(attr.value); + std::optional<uint32_t> integer = ResourceUtils::ParseInt(attr.value); if (integer) { return integer; } @@ -293,7 +293,7 @@ static Maybe<uint32_t> ExtractCompiledInt(const xml::Attribute& attr, std::strin return {}; } -static Maybe<int> ExtractSdkVersion(const xml::Attribute& attr, std::string* out_error) { +static std::optional<int> ExtractSdkVersion(const xml::Attribute& attr, std::string* out_error) { if (attr.compiled_value != nullptr) { const BinaryPrimitive* compiled_prim = ValueCast<BinaryPrimitive>(attr.compiled_value.get()); if (compiled_prim != nullptr) { @@ -307,7 +307,7 @@ static Maybe<int> ExtractSdkVersion(const xml::Attribute& attr, std::string* out const String* compiled_str = ValueCast<String>(attr.compiled_value.get()); if (compiled_str != nullptr) { - Maybe<int> sdk_version = ResourceUtils::ParseSdkVersion(*compiled_str->value); + std::optional<int> sdk_version = ResourceUtils::ParseSdkVersion(*compiled_str->value); if (sdk_version) { return sdk_version; } @@ -320,7 +320,7 @@ static Maybe<int> ExtractSdkVersion(const xml::Attribute& attr, std::string* out } // Fallback to the plain text value if there is one. - Maybe<int> sdk_version = ResourceUtils::ParseSdkVersion(attr.value); + std::optional<int> sdk_version = ResourceUtils::ParseSdkVersion(attr.value); if (sdk_version) { return sdk_version; } @@ -330,8 +330,8 @@ static Maybe<int> ExtractSdkVersion(const xml::Attribute& attr, std::string* out return {}; } -Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res, - IDiagnostics* diag) { +std::optional<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res, + IDiagnostics* diag) { // Make sure the first element is <manifest> with package attribute. const xml::Element* manifest_el = xml_res.root.get(); if (manifest_el == nullptr) { @@ -352,7 +352,7 @@ Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res, } std::string error_msg; - Maybe<std::string> maybe_package = ExtractCompiledString(*package_attr, &error_msg); + std::optional<std::string> maybe_package = ExtractCompiledString(*package_attr, &error_msg); if (!maybe_package) { diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number)) << "invalid package name: " << error_msg); @@ -362,7 +362,7 @@ Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res, if (const xml::Attribute* version_code_attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode")) { - Maybe<uint32_t> maybe_code = ExtractCompiledInt(*version_code_attr, &error_msg); + std::optional<uint32_t> maybe_code = ExtractCompiledInt(*version_code_attr, &error_msg); if (!maybe_code) { diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number)) << "invalid android:versionCode: " << error_msg); @@ -373,7 +373,7 @@ Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res, if (const xml::Attribute* version_code_major_attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor")) { - Maybe<uint32_t> maybe_code = ExtractCompiledInt(*version_code_major_attr, &error_msg); + std::optional<uint32_t> maybe_code = ExtractCompiledInt(*version_code_major_attr, &error_msg); if (!maybe_code) { diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number)) << "invalid android:versionCodeMajor: " << error_msg); @@ -384,7 +384,7 @@ Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res, if (const xml::Attribute* revision_code_attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode")) { - Maybe<uint32_t> maybe_code = ExtractCompiledInt(*revision_code_attr, &error_msg); + std::optional<uint32_t> maybe_code = ExtractCompiledInt(*revision_code_attr, &error_msg); if (!maybe_code) { diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number)) << "invalid android:revisionCode: " << error_msg); @@ -394,7 +394,8 @@ Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res, } if (const xml::Attribute* split_name_attr = manifest_el->FindAttribute({}, "split")) { - Maybe<std::string> maybe_split_name = ExtractCompiledString(*split_name_attr, &error_msg); + std::optional<std::string> maybe_split_name = + ExtractCompiledString(*split_name_attr, &error_msg); if (!maybe_split_name) { diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number)) << "invalid split name: " << error_msg); @@ -406,7 +407,7 @@ Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res, if (const xml::Element* uses_sdk_el = manifest_el->FindChild({}, "uses-sdk")) { if (const xml::Attribute* min_sdk = uses_sdk_el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion")) { - Maybe<int> maybe_sdk = ExtractSdkVersion(*min_sdk, &error_msg); + std::optional<int> maybe_sdk = ExtractSdkVersion(*min_sdk, &error_msg); if (!maybe_sdk) { diag->Error(DiagMessage(xml_res.file.source.WithLine(uses_sdk_el->line_number)) << "invalid android:minSdkVersion: " << error_msg); diff --git a/tools/aapt2/cmd/Util.h b/tools/aapt2/cmd/Util.h index 2a7c62eef678..1b98eb468700 100644 --- a/tools/aapt2/cmd/Util.h +++ b/tools/aapt2/cmd/Util.h @@ -26,14 +26,14 @@ #include "SdkConstants.h" #include "filter/ConfigFilter.h" #include "split/TableSplitter.h" -#include "util/Maybe.h" #include "xml/XmlDom.h" namespace aapt { // Parses a configuration density (ex. hdpi, xxhdpi, 234dpi, anydpi, etc). // Returns Nothing and logs a human friendly error message if the string was not legal. -Maybe<uint16_t> ParseTargetDensityParameter(const android::StringPiece& arg, IDiagnostics* diag); +std::optional<uint16_t> ParseTargetDensityParameter(const android::StringPiece& arg, + IDiagnostics* diag); // Parses a string of the form 'path/to/output.apk:<config>[,<config>...]' and fills in // `out_path` with the path and `out_split` with the set of ConfigDescriptions. @@ -59,8 +59,8 @@ std::unique_ptr<xml::XmlResource> GenerateSplitManifest(const AppInfo& app_info, const SplitConstraints& constraints); // Extracts relevant info from the AndroidManifest.xml. -Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res, - IDiagnostics* diag); +std::optional<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res, + IDiagnostics* diag); // Returns a copy of 'name' which conforms to the regex '[a-zA-Z]+[a-zA-Z0-9_]*' by // replacing nonconforming characters with underscores. diff --git a/tools/aapt2/compile/IdAssigner_test.cpp b/tools/aapt2/compile/IdAssigner_test.cpp index 663776645990..d3575716ae4f 100644 --- a/tools/aapt2/compile/IdAssigner_test.cpp +++ b/tools/aapt2/compile/IdAssigner_test.cpp @@ -57,18 +57,18 @@ TEST_F(IdAssignerTests, AssignIdsWithReservedIds) { ASSERT_TRUE(assigner.Consume(context.get(), table.get())); ASSERT_TRUE(VerifyIds(table.get())); - Maybe<ResourceTable::SearchResult> maybe_result; + std::optional<ResourceTable::SearchResult> maybe_result; // Expect to fill in the gaps between 0x0101XXXX and 0x0104XXXX. maybe_result = table->FindResource(test::ParseNameOrDie("android:dimen/two")); ASSERT_TRUE(maybe_result); - EXPECT_EQ(make_value<ResourceId>(0x01020000), maybe_result.value().entry->id); + EXPECT_EQ(0x01020000, maybe_result.value().entry->id); maybe_result = table->FindResource(test::ParseNameOrDie("android:integer/three")); ASSERT_TRUE(maybe_result); - EXPECT_EQ(make_value<ResourceId>(0x01030000), maybe_result.value().entry->id); + EXPECT_EQ(0x01030000, maybe_result.value().entry->id); // Expect to bypass the reserved 0x0104XXXX IDs and use the next 0x0105XXXX // IDs. @@ -76,17 +76,17 @@ TEST_F(IdAssignerTests, AssignIdsWithReservedIds) { maybe_result = table->FindResource(test::ParseNameOrDie("android:string/five")); ASSERT_TRUE(maybe_result); - EXPECT_EQ(make_value<ResourceId>(0x01050000), maybe_result.value().entry->id); + EXPECT_EQ(0x01050000, maybe_result.value().entry->id); // Expect to fill in the gaps between 0x01040000 and 0x01040006. maybe_result = table->FindResource(test::ParseNameOrDie("android:attr/bar")); ASSERT_TRUE(maybe_result); - EXPECT_EQ(make_value<ResourceId>(0x01040001), maybe_result.value().entry->id); + EXPECT_EQ(0x01040001, maybe_result.value().entry->id); maybe_result = table->FindResource(test::ParseNameOrDie("android:attr/baz")); ASSERT_TRUE(maybe_result); - EXPECT_EQ(make_value<ResourceId>(0x01040002), maybe_result.value().entry->id); + EXPECT_EQ(0x01040002, maybe_result.value().entry->id); } TEST_F(IdAssignerTests, FailWhenNonUniqueIdsAssigned) { @@ -143,7 +143,7 @@ TEST_F(IdAssignerTests, AssignIdsWithIdMap) { ASSERT_TRUE(result); const ResourceTable::SearchResult& search_result = result.value(); - EXPECT_EQ(make_value<ResourceId>(0x01010002), search_result.entry->id); + EXPECT_EQ(0x01010002, search_result.entry->id); } TEST_F(IdAssignerTests, UseAllEntryIds) { diff --git a/tools/aapt2/compile/InlineXmlFormatParser.cpp b/tools/aapt2/compile/InlineXmlFormatParser.cpp index 79b0933a089f..de1c3bb3dd7e 100644 --- a/tools/aapt2/compile/InlineXmlFormatParser.cpp +++ b/tools/aapt2/compile/InlineXmlFormatParser.cpp @@ -56,7 +56,7 @@ class Visitor : public xml::PackageAwareVisitor { return; } - Maybe<Reference> ref = ResourceUtils::ParseXmlAttributeName(attr->value); + std::optional<Reference> ref = ResourceUtils::ParseXmlAttributeName(attr->value); if (!ref) { context_->GetDiagnostics()->Error(DiagMessage(src) << "invalid XML attribute '" << attr->value << "'"); @@ -65,7 +65,7 @@ class Visitor : public xml::PackageAwareVisitor { } const ResourceName& name = ref.value().name.value(); - Maybe<xml::ExtractedPackage> maybe_pkg = TransformPackageAlias(name.package); + std::optional<xml::ExtractedPackage> maybe_pkg = TransformPackageAlias(name.package); if (!maybe_pkg) { context_->GetDiagnostics()->Error(DiagMessage(src) << "invalid namespace prefix '" << name.package << "'"); diff --git a/tools/aapt2/compile/PseudolocaleGenerator.cpp b/tools/aapt2/compile/PseudolocaleGenerator.cpp index 3f574ee8e897..2461438c49b6 100644 --- a/tools/aapt2/compile/PseudolocaleGenerator.cpp +++ b/tools/aapt2/compile/PseudolocaleGenerator.cpp @@ -33,7 +33,7 @@ namespace aapt { // The struct that represents both Span objects and UntranslatableSections. struct UnifiedSpan { // Only present for Span objects. If not present, this was an UntranslatableSection. - Maybe<std::string> tag; + std::optional<std::string> tag; // The UTF-16 index into the string where this span starts. uint32_t first_char; diff --git a/tools/aapt2/configuration/ConfigurationParser.cpp b/tools/aapt2/configuration/ConfigurationParser.cpp index dd06b38f6c01..e7a45851e239 100644 --- a/tools/aapt2/configuration/ConfigurationParser.cpp +++ b/tools/aapt2/configuration/ConfigurationParser.cpp @@ -34,7 +34,6 @@ #include "io/FileSystem.h" #include "io/StringStream.h" #include "util/Files.h" -#include "util/Maybe.h" #include "util/Util.h" #include "xml/XmlActionExecutor.h" #include "xml/XmlDom.h" @@ -113,7 +112,7 @@ std::string GetLabel(const Element* element, IDiagnostics* diag) { } /** Returns the value of the version-code-order attribute for a given element. */ -Maybe<int32_t> GetVersionCodeOrder(const Element* element, IDiagnostics* diag) { +std::optional<int32_t> GetVersionCodeOrder(const Element* element, IDiagnostics* diag) { const xml::Attribute* version = element->FindAttribute("", "version-code-order"); if (version == nullptr) { std::string label = GetLabel(element, diag); @@ -135,7 +134,7 @@ class NamespaceVisitor : public xml::Visitor { /** Copies the values referenced in a configuration group to the target list. */ template <typename T> -bool CopyXmlReferences(const Maybe<std::string>& name, const Group<T>& groups, +bool CopyXmlReferences(const std::optional<std::string>& name, const Group<T>& groups, std::vector<T>* target) { // If there was no item configured, there is nothing to do and no error. if (!name) { @@ -159,7 +158,7 @@ bool CopyXmlReferences(const Maybe<std::string>& name, const Group<T>& groups, * success, or false if the either the placeholder is not found in the name, or the value is not * present and the placeholder was. */ -bool ReplacePlaceholder(const StringPiece& placeholder, const Maybe<StringPiece>& value, +bool ReplacePlaceholder(const StringPiece& placeholder, const std::optional<StringPiece>& value, std::string* name, IDiagnostics* diag) { size_t offset = name->find(placeholder.data()); bool found = (offset != std::string::npos); @@ -207,17 +206,17 @@ xml::XmlNodeAction::ActionFuncWithDiag Bind(configuration::PostProcessingConfigu } /** Converts a ConfiguredArtifact into an OutputArtifact. */ -Maybe<OutputArtifact> ToOutputArtifact(const ConfiguredArtifact& artifact, - const std::string& apk_name, - const PostProcessingConfiguration& config, - IDiagnostics* diag) { +std::optional<OutputArtifact> ToOutputArtifact(const ConfiguredArtifact& artifact, + const std::string& apk_name, + const PostProcessingConfiguration& config, + IDiagnostics* diag) { if (!artifact.name && !config.artifact_format) { diag->Error( DiagMessage() << "Artifact does not have a name and no global name template defined"); return {}; } - Maybe<std::string> artifact_name = + std::optional<std::string> artifact_name = (artifact.name) ? artifact.Name(apk_name, diag) : artifact.ToArtifactName(config.artifact_format.value(), apk_name, diag); @@ -287,9 +286,9 @@ Maybe<OutputArtifact> ToOutputArtifact(const ConfiguredArtifact& artifact, namespace configuration { /** Returns the binary reprasentation of the XML configuration. */ -Maybe<PostProcessingConfiguration> ExtractConfiguration(const std::string& contents, - const std::string& config_path, - IDiagnostics* diag) { +std::optional<PostProcessingConfiguration> ExtractConfiguration(const std::string& contents, + const std::string& config_path, + IDiagnostics* diag) { StringInputStream in(contents); std::unique_ptr<xml::XmlResource> doc = xml::Inflate(&in, diag, Source(config_path)); if (!doc) { @@ -351,7 +350,8 @@ const StringPiece& AbiToString(Abi abi) { /** * Returns the common artifact base name from a template string. */ -Maybe<std::string> ToBaseName(std::string result, const StringPiece& apk_name, IDiagnostics* diag) { +std::optional<std::string> ToBaseName(std::string result, const StringPiece& apk_name, + IDiagnostics* diag) { const StringPiece ext = file::GetExtension(apk_name); size_t end_index = apk_name.to_string().rfind(ext.to_string()); const std::string base_name = @@ -359,8 +359,8 @@ Maybe<std::string> ToBaseName(std::string result, const StringPiece& apk_name, I // Base name is optional. if (result.find("${basename}") != std::string::npos) { - Maybe<StringPiece> maybe_base_name = - base_name.empty() ? Maybe<StringPiece>{} : Maybe<StringPiece>{base_name}; + auto maybe_base_name = base_name.empty() ? std::nullopt + : std::optional<StringPiece>{base_name}; if (!ReplacePlaceholder("${basename}", maybe_base_name, &result, diag)) { return {}; } @@ -383,10 +383,10 @@ Maybe<std::string> ToBaseName(std::string result, const StringPiece& apk_name, I return result; } -Maybe<std::string> ConfiguredArtifact::ToArtifactName(const StringPiece& format, - const StringPiece& apk_name, - IDiagnostics* diag) const { - Maybe<std::string> base = ToBaseName(format.to_string(), apk_name, diag); +std::optional<std::string> ConfiguredArtifact::ToArtifactName(const StringPiece& format, + const StringPiece& apk_name, + IDiagnostics* diag) const { + std::optional<std::string> base = ToBaseName(format.to_string(), apk_name, diag); if (!base) { return {}; } @@ -419,7 +419,8 @@ Maybe<std::string> ConfiguredArtifact::ToArtifactName(const StringPiece& format, return result; } -Maybe<std::string> ConfiguredArtifact::Name(const StringPiece& apk_name, IDiagnostics* diag) const { +std::optional<std::string> ConfiguredArtifact::Name(const StringPiece& apk_name, + IDiagnostics* diag) const { if (!name) { return {}; } @@ -430,7 +431,7 @@ Maybe<std::string> ConfiguredArtifact::Name(const StringPiece& apk_name, IDiagno } // namespace configuration /** Returns a ConfigurationParser for the file located at the provided path. */ -Maybe<ConfigurationParser> ConfigurationParser::ForPath(const std::string& path) { +std::optional<ConfigurationParser> ConfigurationParser::ForPath(const std::string& path) { std::string contents; if (!ReadFileToString(path, &contents, true)) { return {}; @@ -442,9 +443,9 @@ ConfigurationParser::ConfigurationParser(std::string contents, const std::string : contents_(std::move(contents)), config_path_(config_path), diag_(&noop_) { } -Maybe<std::vector<OutputArtifact>> ConfigurationParser::Parse( +std::optional<std::vector<OutputArtifact>> ConfigurationParser::Parse( const android::StringPiece& apk_path) { - Maybe<PostProcessingConfiguration> maybe_config = + std::optional<PostProcessingConfiguration> maybe_config = ExtractConfiguration(contents_, config_path_, diag_); if (!maybe_config) { return {}; @@ -460,7 +461,8 @@ Maybe<std::vector<OutputArtifact>> ConfigurationParser::Parse( int version = 1; for (const ConfiguredArtifact& artifact : config.artifacts) { - Maybe<OutputArtifact> output_artifact = ToOutputArtifact(artifact, apk_name, config, diag_); + std::optional<OutputArtifact> output_artifact = + ToOutputArtifact(artifact, apk_name, config, diag_); if (!output_artifact) { // Defer return an error condition so that all errors are reported. valid = false; @@ -538,7 +540,7 @@ bool AbiGroupTagHandler(PostProcessingConfiguration* config, Element* root_eleme bool valid = true; OrderedEntry<Abi>& entry = config->abi_groups[label]; - Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag); + std::optional<int32_t> order = GetVersionCodeOrder(root_element, diag); if (!order) { valid = false; } else { @@ -589,7 +591,7 @@ bool ScreenDensityGroupTagHandler(PostProcessingConfiguration* config, Element* bool valid = true; OrderedEntry<ConfigDescription>& entry = config->screen_density_groups[label]; - Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag); + std::optional<int32_t> order = GetVersionCodeOrder(root_element, diag); if (!order) { valid = false; } else { @@ -656,7 +658,7 @@ bool LocaleGroupTagHandler(PostProcessingConfiguration* config, Element* root_el bool valid = true; OrderedEntry<ConfigDescription>& entry = config->locale_groups[label]; - Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag); + std::optional<int32_t> order = GetVersionCodeOrder(root_element, diag); if (!order) { valid = false; } else { @@ -724,19 +726,19 @@ bool AndroidSdkTagHandler(PostProcessingConfiguration* config, Element* root_ele entry.label = attr.value; valid_attr = true; } else if (attr.name == "minSdkVersion") { - Maybe<int> version = ResourceUtils::ParseSdkVersion(attr.value); + std::optional<int> version = ResourceUtils::ParseSdkVersion(attr.value); if (version) { valid_attr = true; entry.min_sdk_version = version.value(); } } else if (attr.name == "targetSdkVersion") { - Maybe<int> version = ResourceUtils::ParseSdkVersion(attr.value); + std::optional<int> version = ResourceUtils::ParseSdkVersion(attr.value); if (version) { valid_attr = true; entry.target_sdk_version = version; } } else if (attr.name == "maxSdkVersion") { - Maybe<int> version = ResourceUtils::ParseSdkVersion(attr.value); + std::optional<int> version = ResourceUtils::ParseSdkVersion(attr.value); if (version) { valid_attr = true; entry.max_sdk_version = version; @@ -778,7 +780,7 @@ bool GlTextureGroupTagHandler(PostProcessingConfiguration* config, Element* root bool valid = true; OrderedEntry<GlTexture>& entry = config->gl_texture_groups[label]; - Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag); + std::optional<int32_t> order = GetVersionCodeOrder(root_element, diag); if (!order) { valid = false; } else { @@ -828,7 +830,7 @@ bool DeviceFeatureGroupTagHandler(PostProcessingConfiguration* config, Element* bool valid = true; OrderedEntry<DeviceFeature>& entry = config->device_feature_groups[label]; - Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag); + std::optional<int32_t> order = GetVersionCodeOrder(root_element, diag); if (!order) { valid = false; } else { diff --git a/tools/aapt2/configuration/ConfigurationParser.h b/tools/aapt2/configuration/ConfigurationParser.h index b9e3be9393c9..195b4baac319 100644 --- a/tools/aapt2/configuration/ConfigurationParser.h +++ b/tools/aapt2/configuration/ConfigurationParser.h @@ -17,6 +17,7 @@ #ifndef AAPT2_CONFIGURATION_H #define AAPT2_CONFIGURATION_H +#include <optional> #include <set> #include <string> #include <unordered_map> @@ -25,7 +26,6 @@ #include "androidfw/ConfigDescription.h" #include "Diagnostics.h" -#include "util/Maybe.h" namespace aapt { @@ -55,9 +55,9 @@ const android::StringPiece& AbiToString(Abi abi); */ struct Locale { /** The ISO<?> standard locale language code. */ - Maybe<std::string> lang; + std::optional<std::string> lang; /** The ISO<?> standard locale region code. */ - Maybe<std::string> region; + std::optional<std::string> region; inline friend bool operator==(const Locale& lhs, const Locale& rhs) { return lhs.lang == rhs.lang && lhs.region == rhs.region; @@ -74,9 +74,9 @@ struct AndroidManifest { struct AndroidSdk { std::string label; int min_sdk_version; // min_sdk_version is mandatory if splitting by SDK. - Maybe<int> target_sdk_version; - Maybe<int> max_sdk_version; - Maybe<AndroidManifest> manifest; + std::optional<int> target_sdk_version; + std::optional<int> max_sdk_version; + std::optional<AndroidManifest> manifest; static AndroidSdk ForMinSdk(int min_sdk) { AndroidSdk sdk; @@ -112,7 +112,7 @@ struct OutputArtifact { std::vector<Abi> abis; std::vector<android::ConfigDescription> screen_densities; std::vector<android::ConfigDescription> locales; - Maybe<AndroidSdk> android_sdk; + std::optional<AndroidSdk> android_sdk; std::vector<DeviceFeature> features; std::vector<GlTexture> textures; @@ -136,7 +136,7 @@ class ConfigurationParser { public: /** Returns a ConfigurationParser for the file located at the provided path. */ - static Maybe<ConfigurationParser> ForPath(const std::string& path); + static std::optional<ConfigurationParser> ForPath(const std::string& path); /** Returns a ConfigurationParser for the configuration in the provided file contents. */ static ConfigurationParser ForContents(const std::string& contents, const std::string& path) { @@ -154,7 +154,8 @@ class ConfigurationParser { * Parses the configuration file and returns the results. If the configuration could not be parsed * the result is empty and any errors will be displayed with the provided diagnostics context. */ - Maybe<std::vector<configuration::OutputArtifact>> Parse(const android::StringPiece& apk_path); + std::optional<std::vector<configuration::OutputArtifact>> Parse( + const android::StringPiece& apk_path); protected: /** diff --git a/tools/aapt2/configuration/ConfigurationParser.internal.h b/tools/aapt2/configuration/ConfigurationParser.internal.h index c541688bc018..42ef51591d4f 100644 --- a/tools/aapt2/configuration/ConfigurationParser.internal.h +++ b/tools/aapt2/configuration/ConfigurationParser.internal.h @@ -84,8 +84,8 @@ class ComparisonChain { * have not been able to determine the sort order with the previous comparisons. */ template <typename T> - ComparisonChain& Add(const Group<T>& groups, const Maybe<std::string>& lhs, - const Maybe<std::string>& rhs) { + ComparisonChain& Add(const Group<T>& groups, const std::optional<std::string>& lhs, + const std::optional<std::string>& rhs) { return Add(GetGroupOrder(groups, lhs), GetGroupOrder(groups, rhs)); } @@ -108,7 +108,7 @@ class ComparisonChain { private: template <typename T> - inline size_t GetGroupOrder(const Entry<T>& groups, const Maybe<std::string>& label) { + inline size_t GetGroupOrder(const Entry<T>& groups, const std::optional<std::string>& label) { if (!label) { return std::numeric_limits<size_t>::max(); } @@ -122,32 +122,33 @@ class ComparisonChain { /** Output artifact configuration options. */ struct ConfiguredArtifact { /** Name to use for output of processing foo.apk -> foo.<name>.apk. */ - Maybe<std::string> name; + std::optional<std::string> name; /** If present, uses the ABI group with this name. */ - Maybe<std::string> abi_group; + std::optional<std::string> abi_group; /** If present, uses the screen density group with this name. */ - Maybe<std::string> screen_density_group; + std::optional<std::string> screen_density_group; /** If present, uses the locale group with this name. */ - Maybe<std::string> locale_group; + std::optional<std::string> locale_group; /** If present, uses the Android SDK with this name. */ - Maybe<std::string> android_sdk; + std::optional<std::string> android_sdk; /** If present, uses the device feature group with this name. */ - Maybe<std::string> device_feature_group; + std::optional<std::string> device_feature_group; /** If present, uses the OpenGL texture group with this name. */ - Maybe<std::string> gl_texture_group; + std::optional<std::string> gl_texture_group; /** Convert an artifact name template into a name string based on configuration contents. */ - Maybe<std::string> ToArtifactName(const android::StringPiece& format, - const android::StringPiece& apk_name, IDiagnostics* diag) const; + std::optional<std::string> ToArtifactName(const android::StringPiece& format, + const android::StringPiece& apk_name, + IDiagnostics* diag) const; /** Convert an artifact name template into a name string based on configuration contents. */ - Maybe<std::string> Name(const android::StringPiece& apk_name, IDiagnostics* diag) const; + std::optional<std::string> Name(const android::StringPiece& apk_name, IDiagnostics* diag) const; }; /** AAPT2 XML configuration file binary representation. */ struct PostProcessingConfiguration { std::vector<ConfiguredArtifact> artifacts; - Maybe<std::string> artifact_format; + std::optional<std::string> artifact_format; Group<Abi> abi_groups; Group<android::ConfigDescription> screen_density_groups; @@ -212,9 +213,9 @@ struct PostProcessingConfiguration { }; /** Parses the provided XML document returning the post processing configuration. */ -Maybe<PostProcessingConfiguration> ExtractConfiguration(const std::string& contents, - const std::string& config_path, - IDiagnostics* diag); +std::optional<PostProcessingConfiguration> ExtractConfiguration(const std::string& contents, + const std::string& config_path, + IDiagnostics* diag); namespace handler { diff --git a/tools/aapt2/configuration/ConfigurationParser_test.cpp b/tools/aapt2/configuration/ConfigurationParser_test.cpp index e5b3107877cb..e5eacccb682e 100644 --- a/tools/aapt2/configuration/ConfigurationParser_test.cpp +++ b/tools/aapt2/configuration/ConfigurationParser_test.cpp @@ -31,11 +31,6 @@ using ::android::ConfigDescription; namespace aapt { namespace configuration { -void PrintTo(const AndroidSdk& sdk, std::ostream* os) { - *os << "SDK: min=" << sdk.min_sdk_version - << ", target=" << sdk.target_sdk_version.value_or_default(-1) - << ", max=" << sdk.max_sdk_version.value_or_default(-1); -} bool operator==(const ConfiguredArtifact& lhs, const ConfiguredArtifact& rhs) { return lhs.name == rhs.name && lhs.abi_group == rhs.abi_group && @@ -45,20 +40,6 @@ bool operator==(const ConfiguredArtifact& lhs, const ConfiguredArtifact& rhs) { lhs.gl_texture_group == rhs.gl_texture_group; } -std::ostream& operator<<(std::ostream& out, const Maybe<std::string>& value) { - PrintTo(value, &out); - return out; -} - -void PrintTo(const ConfiguredArtifact& artifact, std::ostream* os) { - *os << "\n{" - << "\n name: " << artifact.name << "\n sdk: " << artifact.android_sdk - << "\n abi: " << artifact.abi_group << "\n density: " << artifact.screen_density_group - << "\n locale: " << artifact.locale_group - << "\n features: " << artifact.device_feature_group - << "\n textures: " << artifact.gl_texture_group << "\n}\n"; -} - namespace handler { namespace { @@ -186,7 +167,7 @@ TEST_F(ConfigurationParserTest, ForPath_NoFile) { } TEST_F(ConfigurationParserTest, ExtractConfiguration) { - Maybe<PostProcessingConfiguration> maybe_config = + std::optional<PostProcessingConfiguration> maybe_config = ExtractConfiguration(kValidConfig, "fake.xml", &diag_); PostProcessingConfiguration config = maybe_config.value(); @@ -928,7 +909,8 @@ TEST(ArtifactTest, Nesting) { EXPECT_FALSE(x86.ToArtifactName("something.${abi${density}}.apk", "", &diag)); - const Maybe<std::string>& name = x86.ToArtifactName("something.${abi${abi}}.apk", "", &diag); + const std::optional<std::string>& name = + x86.ToArtifactName("something.${abi${abi}}.apk", "", &diag); ASSERT_TRUE(name); EXPECT_EQ(name.value(), "something.${abix86}.apk"); } diff --git a/tools/aapt2/format/Archive.cpp b/tools/aapt2/format/Archive.cpp index 41f01a01ed7c..c20b053c37b1 100644 --- a/tools/aapt2/format/Archive.cpp +++ b/tools/aapt2/format/Archive.cpp @@ -43,7 +43,7 @@ class DirectoryWriter : public IArchiveWriter { bool Open(const StringPiece& out_dir) { dir_ = out_dir.to_string(); file::FileType type = file::GetFileType(dir_); - if (type == file::FileType::kNonexistant) { + if (type == file::FileType::kNonExistant) { error_ = "directory does not exist"; return false; } else if (type != file::FileType::kDirectory) { diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp index 8139d7385092..cd1c0af702cf 100644 --- a/tools/aapt2/format/binary/TableFlattener_test.cpp +++ b/tools/aapt2/format/binary/TableFlattener_test.cpp @@ -123,7 +123,7 @@ class TableFlattenerTest : public ::testing::Test { return ::testing::AssertionFailure() << "failed to find resource name"; } - Maybe<ResourceName> resName = ResourceUtils::ToResourceName(actual_name); + std::optional<ResourceName> resName = ResourceUtils::ToResourceName(actual_name); if (!resName) { return ::testing::AssertionFailure() << "expected name '" << expected_res_name << "' but got '" @@ -423,7 +423,7 @@ TEST_F(TableFlattenerTest, FlattenSharedLibrary) { ResourceTable result; ASSERT_TRUE(Flatten(context.get(), {}, table.get(), &result)); - Maybe<ResourceTable::SearchResult> search_result = + std::optional<ResourceTable::SearchResult> search_result = result.FindResource(test::ParseNameOrDie("lib:id/foo")); ASSERT_TRUE(search_result); EXPECT_EQ(0x00u, search_result.value().entry->id.value().package_id()); @@ -454,7 +454,7 @@ TEST_F(TableFlattenerTest, FlattenSharedLibraryWithStyle) { ResourceTable result; ASSERT_TRUE(Flatten(context.get(), {}, table.get(), &result)); - Maybe<ResourceTable::SearchResult> search_result = + std::optional<ResourceTable::SearchResult> search_result = result.FindResource(test::ParseNameOrDie("lib:style/Theme")); ASSERT_TRUE(search_result); EXPECT_EQ(0x00030001u, search_result.value().entry->id.value()); diff --git a/tools/aapt2/format/binary/XmlFlattener.cpp b/tools/aapt2/format/binary/XmlFlattener.cpp index afbaae4ee2a8..cdbe8828b29b 100644 --- a/tools/aapt2/format/binary/XmlFlattener.cpp +++ b/tools/aapt2/format/binary/XmlFlattener.cpp @@ -264,7 +264,7 @@ class XmlFlattenerVisitor : public xml::ConstVisitor { } std::string processed_str; - Maybe<StringPiece> compiled_text; + std::optional<StringPiece> compiled_text; if (xml_attr->compiled_value != nullptr) { // Make sure we're not flattening a String. A String can be referencing a string from // a different StringPool than we're using here to build the binary XML. diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp index 6042ba89bf8a..f3b7f758e170 100644 --- a/tools/aapt2/format/proto/ProtoSerialize.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize.cpp @@ -438,7 +438,7 @@ static pb::Reference_Type SerializeReferenceTypeToPb(Reference::Type type) { } static void SerializeReferenceToPb(const Reference& ref, pb::Reference* pb_ref) { - pb_ref->set_id(ref.id.value_or_default(ResourceId(0x0)).id); + pb_ref->set_id(ref.id.value_or(ResourceId(0x0)).id); if (ref.name) { pb_ref->set_name(ref.name.value().to_string()); @@ -759,13 +759,13 @@ void SerializeXmlToPb(const xml::Element& el, pb::XmlNode* out_node, pb_attr->set_namespace_uri(attr.namespace_uri); pb_attr->set_value(attr.value); if (attr.compiled_attribute) { - const ResourceId attr_id = attr.compiled_attribute.value().id.value_or_default({}); + const ResourceId attr_id = attr.compiled_attribute.value().id.value_or(ResourceId{}); pb_attr->set_resource_id(attr_id.id); } if (attr.compiled_value != nullptr) { SerializeItemToPb(*attr.compiled_value, pb_attr->mutable_compiled_item()); pb::SourcePosition* pb_src = pb_attr->mutable_source(); - pb_src->set_line_number(attr.compiled_value->GetSource().line.value_or_default(0)); + pb_src->set_line_number(attr.compiled_value->GetSource().line.value_or(0)); } } diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp index 38c811fe3619..d1d72e012b31 100644 --- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp @@ -189,7 +189,7 @@ TEST(ProtoSerializeTest, SerializeSinglePackage) { ASSERT_THAT(new_id, NotNull()); EXPECT_THAT(new_id->IsWeak(), Eq(id->IsWeak())); - Maybe<ResourceTable::SearchResult> result = + std::optional<ResourceTable::SearchResult> result = new_table.FindResource(test::ParseNameOrDie("com.app.a:layout/main")); ASSERT_TRUE(result); @@ -234,7 +234,7 @@ TEST(ProtoSerializeTest, SerializeSinglePackage) { EXPECT_THAT(actual_styled_str->value->spans[0].first_char, Eq(0u)); EXPECT_THAT(actual_styled_str->value->spans[0].last_char, Eq(4u)); - Maybe<ResourceTable::SearchResult> search_result = + std::optional<ResourceTable::SearchResult> search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:integer/overlayable")); ASSERT_TRUE(search_result); ASSERT_THAT(search_result.value().entry, NotNull()); @@ -637,7 +637,7 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error)); EXPECT_THAT(error, IsEmpty()); - Maybe<ResourceTable::SearchResult> search_result = + std::optional<ResourceTable::SearchResult> search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/foo")); ASSERT_TRUE(search_result); ASSERT_TRUE(search_result.value().entry->overlayable_item); diff --git a/tools/aapt2/io/FileSystem.cpp b/tools/aapt2/io/FileSystem.cpp index e15f935cad27..fc2e45e74b4d 100644 --- a/tools/aapt2/io/FileSystem.cpp +++ b/tools/aapt2/io/FileSystem.cpp @@ -21,11 +21,10 @@ #include "android-base/errors.h" #include "androidfw/StringPiece.h" #include "utils/FileMap.h" - #include "Source.h" #include "io/FileStream.h" #include "util/Files.h" -#include "util/Maybe.h" + #include "util/Util.h" using ::android::StringPiece; @@ -38,7 +37,7 @@ RegularFile::RegularFile(const Source& source) : source_(source) {} std::unique_ptr<IData> RegularFile::OpenAsData() { android::FileMap map; - if (Maybe<android::FileMap> map = file::MmapPath(source_.path, nullptr)) { + if (std::optional<android::FileMap> map = file::MmapPath(source_.path, nullptr)) { if (map.value().getDataPtr() && map.value().getDataLength() > 0) { return util::make_unique<MmappedData>(std::move(map.value())); } diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp index de6524dc7027..3b3c6e187aa6 100644 --- a/tools/aapt2/java/JavaClassGenerator.cpp +++ b/tools/aapt2/java/JavaClassGenerator.cpp @@ -204,7 +204,7 @@ bool JavaClassGenerator::SkipSymbol(Visibility::Level level) { } // Whether or not to skip writing this symbol. -bool JavaClassGenerator::SkipSymbol(const Maybe<SymbolTable::Symbol>& symbol) { +bool JavaClassGenerator::SkipSymbol(const std::optional<SymbolTable::Symbol>& symbol) { return !symbol || (options_.types == JavaClassGeneratorOptions::SymbolTypes::kPublic && !symbol.value().is_public); } @@ -212,12 +212,12 @@ bool JavaClassGenerator::SkipSymbol(const Maybe<SymbolTable::Symbol>& symbol) { struct StyleableAttr { const Reference* attr_ref = nullptr; std::string field_name; - Maybe<SymbolTable::Symbol> symbol; + std::optional<SymbolTable::Symbol> symbol; }; static bool operator<(const StyleableAttr& lhs, const StyleableAttr& rhs) { - const ResourceId lhs_id = lhs.attr_ref->id.value_or_default(ResourceId(0)); - const ResourceId rhs_id = rhs.attr_ref->id.value_or_default(ResourceId(0)); + const ResourceId lhs_id = lhs.attr_ref->id.value_or(ResourceId(0)); + const ResourceId rhs_id = rhs.attr_ref->id.value_or(ResourceId(0)); if (lhs_id == rhs_id) { return lhs.attr_ref->name.value() < rhs.attr_ref->name.value(); } @@ -362,7 +362,7 @@ bool JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const Res array_def->AddElement(field_name); r_txt_contents = field_name.ref; } else { - const ResourceId attr_id = attr.attr_ref->id.value_or_default(ResourceId(0)); + const ResourceId attr_id = attr.attr_ref->id.value_or(ResourceId(0)); array_def->AddElement(attr_id); r_txt_contents = to_string(attr_id); } @@ -504,9 +504,9 @@ void JavaClassGenerator::ProcessResource(const ResourceNameRef& name, const Reso } } -Maybe<std::string> JavaClassGenerator::UnmangleResource(const StringPiece& package_name, - const StringPiece& package_name_to_generate, - const ResourceEntry& entry) { +std::optional<std::string> JavaClassGenerator::UnmangleResource( + const StringPiece& package_name, const StringPiece& package_name_to_generate, + const ResourceEntry& entry) { if (SkipSymbol(entry.visibility.level)) { return {}; } @@ -535,7 +535,7 @@ bool JavaClassGenerator::ProcessType(const StringPiece& package_name_to_generate MethodDefinition* out_rewrite_method_def, Printer* r_txt_printer) { for (const auto& entry : type.entries) { - const Maybe<std::string> unmangled_name = + const std::optional<std::string> unmangled_name = UnmangleResource(package.name, package_name_to_generate, *entry); if (!unmangled_name) { continue; diff --git a/tools/aapt2/java/JavaClassGenerator.h b/tools/aapt2/java/JavaClassGenerator.h index d9d1b39805f9..b45a2f12db35 100644 --- a/tools/aapt2/java/JavaClassGenerator.h +++ b/tools/aapt2/java/JavaClassGenerator.h @@ -46,7 +46,7 @@ struct JavaClassGeneratorOptions { // If set, generates code to rewrite the package ID of resources. // Implies use_final == true. Default is unset. - Maybe<OnResourcesLoadedCallbackOptions> rewrite_callback_options; + std::optional<OnResourcesLoadedCallbackOptions> rewrite_callback_options; enum class SymbolTypes { kAll, @@ -83,13 +83,13 @@ class JavaClassGenerator { private: bool SkipSymbol(Visibility::Level state); - bool SkipSymbol(const Maybe<SymbolTable::Symbol>& symbol); + bool SkipSymbol(const std::optional<SymbolTable::Symbol>& symbol); // Returns the unmangled resource entry name if the unmangled package is the same as // package_name_to_generate. Returns nothing if the resource should be skipped. - Maybe<std::string> UnmangleResource(const android::StringPiece& package_name, - const android::StringPiece& package_name_to_generate, - const ResourceEntry& entry); + std::optional<std::string> UnmangleResource(const android::StringPiece& package_name, + const android::StringPiece& package_name_to_generate, + const ResourceEntry& entry); bool ProcessType(const android::StringPiece& package_name_to_generate, const ResourceTablePackage& package, const ResourceTableType& type, diff --git a/tools/aapt2/java/ManifestClassGenerator.cpp b/tools/aapt2/java/ManifestClassGenerator.cpp index 09ea03b23c9a..a0db41baecb4 100644 --- a/tools/aapt2/java/ManifestClassGenerator.cpp +++ b/tools/aapt2/java/ManifestClassGenerator.cpp @@ -19,19 +19,17 @@ #include <algorithm> #include "Source.h" -#include "java/AnnotationProcessor.h" #include "java/ClassDefinition.h" #include "java/JavaClassGenerator.h" #include "text/Unicode.h" -#include "util/Maybe.h" #include "xml/XmlDom.h" using ::aapt::text::IsJavaIdentifier; namespace aapt { -static Maybe<std::string> ExtractJavaIdentifier(IDiagnostics* diag, const Source& source, - const std::string& value) { +static std::optional<std::string> ExtractJavaIdentifier(IDiagnostics* diag, const Source& source, + const std::string& value) { std::string result = value; size_t pos = value.rfind('.'); if (pos != std::string::npos) { @@ -63,7 +61,7 @@ static bool WriteSymbol(const Source& source, IDiagnostics* diag, xml::Element* return false; } - Maybe<std::string> result = + std::optional<std::string> result = ExtractJavaIdentifier(diag, source.WithLine(el->line_number), attr->value); if (!result) { return false; diff --git a/tools/aapt2/java/ProguardRules.cpp b/tools/aapt2/java/ProguardRules.cpp index d9a4caa34e0d..b939f354e89f 100644 --- a/tools/aapt2/java/ProguardRules.cpp +++ b/tools/aapt2/java/ProguardRules.cpp @@ -48,7 +48,7 @@ class BaseVisitor : public xml::Visitor { void Visit(xml::Element* node) override { if (!node->namespace_uri.empty()) { - Maybe<xml::ExtractedPackage> maybe_package = + std::optional<xml::ExtractedPackage> maybe_package = xml::ExtractPackageFromNamespace(node->namespace_uri); if (maybe_package) { // This is a custom view, let's figure out the class name from this. @@ -270,14 +270,16 @@ class ManifestVisitor : public BaseVisitor { get_name = true; xml::Attribute* attr = node->FindAttribute(xml::kSchemaAndroid, "backupAgent"); if (attr) { - Maybe<std::string> result = util::GetFullyQualifiedClassName(package_, attr->value); + std::optional<std::string> result = + util::GetFullyQualifiedClassName(package_, attr->value); if (result) { AddClass(node->line_number, result.value(), ""); } } attr = node->FindAttribute(xml::kSchemaAndroid, "appComponentFactory"); if (attr) { - Maybe<std::string> result = util::GetFullyQualifiedClassName(package_, attr->value); + std::optional<std::string> result = + util::GetFullyQualifiedClassName(package_, attr->value); if (result) { AddClass(node->line_number, result.value(), ""); } @@ -285,7 +287,8 @@ class ManifestVisitor : public BaseVisitor { attr = node->FindAttribute(xml::kSchemaAndroid, "zygotePreloadName"); if (attr) { - Maybe<std::string> result = util::GetFullyQualifiedClassName(package_, attr->value); + std::optional<std::string> result = + util::GetFullyQualifiedClassName(package_, attr->value); if (result) { AddClass(node->line_number, result.value(), ""); } @@ -317,7 +320,8 @@ class ManifestVisitor : public BaseVisitor { get_name = attr != nullptr; if (get_name) { - Maybe<std::string> result = util::GetFullyQualifiedClassName(package_, attr->value); + std::optional<std::string> result = + util::GetFullyQualifiedClassName(package_, attr->value); if (result) { AddClass(node->line_number, result.value(), ""); } diff --git a/tools/aapt2/link/AutoVersioner.cpp b/tools/aapt2/link/AutoVersioner.cpp index 876494e617a6..328ac97090a8 100644 --- a/tools/aapt2/link/AutoVersioner.cpp +++ b/tools/aapt2/link/AutoVersioner.cpp @@ -90,7 +90,7 @@ bool AutoVersioner::Consume(IAaptContext* context, ResourceTable* table) { } if (Style* style = ValueCast<Style>(config_value->value.get())) { - Maybe<ApiVersion> min_sdk_stripped; + std::optional<ApiVersion> min_sdk_stripped; std::vector<Style::Entry> stripped; auto iter = style->entries.begin(); diff --git a/tools/aapt2/link/AutoVersioner_test.cpp b/tools/aapt2/link/AutoVersioner_test.cpp index 02fd00bba439..8179d46145ca 100644 --- a/tools/aapt2/link/AutoVersioner_test.cpp +++ b/tools/aapt2/link/AutoVersioner_test.cpp @@ -87,25 +87,27 @@ TEST(AutoVersionerTest, VersionStylesForTable) { Style* style = test::GetValueForConfig<Style>(table.get(), "app:style/Foo", test::ParseConfigOrDie("v4")); ASSERT_THAT(style, NotNull()); ASSERT_EQ(style->entries.size(), 1u); - EXPECT_EQ(make_value(test::ParseNameOrDie("android:attr/onClick")), style->entries.front().key.name); + EXPECT_EQ(test::ParseNameOrDie("android:attr/onClick"), style->entries.front().key.name); style = test::GetValueForConfig<Style>(table.get(), "app:style/Foo", test::ParseConfigOrDie("v13")); ASSERT_THAT(style, NotNull()); ASSERT_EQ(style->entries.size(), 2u); - EXPECT_EQ(make_value(test::ParseNameOrDie("android:attr/onClick")),style->entries[0].key.name); - EXPECT_EQ(make_value(test::ParseNameOrDie("android:attr/requiresSmallestWidthDp")), style->entries[1].key.name); + EXPECT_EQ(test::ParseNameOrDie("android:attr/onClick"), style->entries[0].key.name); + EXPECT_EQ(test::ParseNameOrDie("android:attr/requiresSmallestWidthDp"), + style->entries[1].key.name); style = test::GetValueForConfig<Style>(table.get(), "app:style/Foo", test::ParseConfigOrDie("v17")); ASSERT_THAT(style, NotNull()); ASSERT_EQ(style->entries.size(), 3u); - EXPECT_EQ(make_value(test::ParseNameOrDie("android:attr/onClick")), style->entries[0].key.name); - EXPECT_EQ(make_value(test::ParseNameOrDie("android:attr/requiresSmallestWidthDp")), style->entries[1].key.name); - EXPECT_EQ(make_value(test::ParseNameOrDie("android:attr/paddingStart")), style->entries[2].key.name); + EXPECT_EQ(test::ParseNameOrDie("android:attr/onClick"), style->entries[0].key.name); + EXPECT_EQ(test::ParseNameOrDie("android:attr/requiresSmallestWidthDp"), + style->entries[1].key.name); + EXPECT_EQ(test::ParseNameOrDie("android:attr/paddingStart"), style->entries[2].key.name); style = test::GetValueForConfig<Style>(table.get(), "app:style/Foo", test::ParseConfigOrDie("v21")); ASSERT_THAT(style, NotNull()); ASSERT_EQ(1u, style->entries.size()); - EXPECT_EQ(make_value(test::ParseNameOrDie("android:attr/paddingEnd")), style->entries.front().key.name); + EXPECT_EQ(test::ParseNameOrDie("android:attr/paddingEnd"), style->entries.front().key.name); } } // namespace aapt diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp index 8abd9dec56be..1bb06964e31c 100644 --- a/tools/aapt2/link/ManifestFixer.cpp +++ b/tools/aapt2/link/ManifestFixer.cpp @@ -52,7 +52,7 @@ static bool NameIsJavaClassName(xml::Element* el, xml::Attribute* attr, // We allow unqualified class names (ie: .HelloActivity) // Since we don't know the package name, we can just make a fake one here and // the test will be identical as long as the real package name is valid too. - Maybe<std::string> fully_qualified_class_name = + std::optional<std::string> fully_qualified_class_name = util::GetFullyQualifiedClassName("a", attr->value); StringPiece qualified_class_name = fully_qualified_class_name @@ -146,7 +146,7 @@ static bool AutoGenerateIsFeatureSplit(xml::Element* el, SourcePathDiagnostics* // Now inject the android:isFeatureSplit="true" attribute. xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, kIsFeatureSplit); if (attr != nullptr) { - if (!ResourceUtils::ParseBool(attr->value).value_or_default(false)) { + if (!ResourceUtils::ParseBool(attr->value).value_or(false)) { // The isFeatureSplit attribute is false, which conflicts with the use // of "featureSplit". diag->Error(DiagMessage(el->line_number) @@ -523,7 +523,8 @@ static void FullyQualifyClassName(const StringPiece& package, const StringPiece& const StringPiece& attr_name, xml::Element* el) { xml::Attribute* attr = el->FindAttribute(attr_ns, attr_name); if (attr != nullptr) { - if (Maybe<std::string> new_value = util::GetFullyQualifiedClassName(package, attr->value)) { + if (std::optional<std::string> new_value = + util::GetFullyQualifiedClassName(package, attr->value)) { attr->value = std::move(new_value.value()); } } diff --git a/tools/aapt2/link/ManifestFixer.h b/tools/aapt2/link/ManifestFixer.h index 34ad8d586df1..d5d1d1770e1c 100644 --- a/tools/aapt2/link/ManifestFixer.h +++ b/tools/aapt2/link/ManifestFixer.h @@ -22,7 +22,7 @@ #include "android-base/macros.h" #include "process/IResourceTableConsumer.h" -#include "util/Maybe.h" + #include "xml/XmlActionExecutor.h" #include "xml/XmlDom.h" @@ -30,47 +30,47 @@ namespace aapt { struct ManifestFixerOptions { // The minimum SDK version to set if no 'android:minSdkVersion' is defined in a <uses-sdk> tag. - Maybe<std::string> min_sdk_version_default; + std::optional<std::string> min_sdk_version_default; // The target SDK version to set if no 'android:targetSdkVersion' is defined in a <uses-sdk> tag. - Maybe<std::string> target_sdk_version_default; + std::optional<std::string> target_sdk_version_default; // The Android package to use instead of the one defined in 'package' in <manifest>. // This also renames all relative package/class names in the manifest to fully qualified // Java names. - Maybe<std::string> rename_manifest_package; + std::optional<std::string> rename_manifest_package; // The Android package to use instead of the one defined in 'android:targetPackage' in // <instrumentation>. - Maybe<std::string> rename_instrumentation_target_package; + std::optional<std::string> rename_instrumentation_target_package; // The Android package to use instead of the one defined in 'android:targetPackage' in // <overlay>. - Maybe<std::string> rename_overlay_target_package; + std::optional<std::string> rename_overlay_target_package; // The version name to set if 'android:versionName' is not defined in <manifest> or if // replace_version is set. - Maybe<std::string> version_name_default; + std::optional<std::string> version_name_default; // The version code to set if 'android:versionCode' is not defined in <manifest> or if // replace_version is set. - Maybe<std::string> version_code_default; + std::optional<std::string> version_code_default; // The version code to set if 'android:versionCodeMajor' is not defined in <manifest> or if // replace_version is set. - Maybe<std::string> version_code_major_default; + std::optional<std::string> version_code_major_default; // The revision code to set if 'android:revisionCode' is not defined in <manifest> or if // replace_version is set. - Maybe<std::string> revision_code_default; + std::optional<std::string> revision_code_default; // The version of the framework being compiled against to set for 'android:compileSdkVersion' in // the <manifest> tag. - Maybe<std::string> compile_sdk_version; + std::optional<std::string> compile_sdk_version; // The version codename of the framework being compiled against to set for // 'android:compileSdkVersionCodename' in the <manifest> tag. - Maybe<std::string> compile_sdk_version_codename; + std::optional<std::string> compile_sdk_version_codename; // Whether validation errors should be treated only as warnings. If this is 'true', then an // incorrect node will not result in an error, but only as a warning, and the parsing will diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp index 4ac25bd6a0e0..47c804c6bf71 100644 --- a/tools/aapt2/link/ReferenceLinker.cpp +++ b/tools/aapt2/link/ReferenceLinker.cpp @@ -190,7 +190,8 @@ class EmptyDeclStack : public xml::IPackageDeclStack { public: EmptyDeclStack() = default; - Maybe<xml::ExtractedPackage> TransformPackageAlias(const StringPiece& alias) const override { + std::optional<xml::ExtractedPackage> TransformPackageAlias( + const StringPiece& alias) const override { if (alias.empty()) { return xml::ExtractedPackage{{}, true /*private*/}; } @@ -206,7 +207,8 @@ struct MacroDeclStack : public xml::IPackageDeclStack { : alias_namespaces_(std::move(namespaces)) { } - Maybe<xml::ExtractedPackage> TransformPackageAlias(const StringPiece& alias) const override { + std::optional<xml::ExtractedPackage> TransformPackageAlias( + const StringPiece& alias) const override { if (alias.empty()) { return xml::ExtractedPackage{{}, true /*private*/}; } @@ -322,11 +324,11 @@ const SymbolTable::Symbol* ReferenceLinker::ResolveAttributeCheckVisibility( return symbol; } -Maybe<xml::AaptAttribute> ReferenceLinker::CompileXmlAttribute(const Reference& reference, - const CallSite& callsite, - IAaptContext* context, - SymbolTable* symbols, - std::string* out_error) { +std::optional<xml::AaptAttribute> ReferenceLinker::CompileXmlAttribute(const Reference& reference, + const CallSite& callsite, + IAaptContext* context, + SymbolTable* symbols, + std::string* out_error) { const SymbolTable::Symbol* symbol = ResolveAttributeCheckVisibility(reference, callsite, context, symbols, out_error); if (!symbol) { diff --git a/tools/aapt2/link/ReferenceLinker.h b/tools/aapt2/link/ReferenceLinker.h index 770f1e500ac0..b46085397c52 100644 --- a/tools/aapt2/link/ReferenceLinker.h +++ b/tools/aapt2/link/ReferenceLinker.h @@ -97,11 +97,11 @@ class ReferenceLinker : public IResourceTableConsumer { // Resolves the attribute reference and returns an xml::AaptAttribute if successful. // If resolution fails, outError holds the error message. - static Maybe<xml::AaptAttribute> CompileXmlAttribute(const Reference& reference, - const CallSite& callsite, - IAaptContext* context, - SymbolTable* symbols, - std::string* out_error); + static std::optional<xml::AaptAttribute> CompileXmlAttribute(const Reference& reference, + const CallSite& callsite, + IAaptContext* context, + SymbolTable* symbols, + std::string* out_error); // Writes the resource name to the DiagMessage, using the // "orig_name (aka <transformed_name>)" syntax. diff --git a/tools/aapt2/link/ReferenceLinker_test.cpp b/tools/aapt2/link/ReferenceLinker_test.cpp index 2d8f0d39053f..97bdd3ebae66 100644 --- a/tools/aapt2/link/ReferenceLinker_test.cpp +++ b/tools/aapt2/link/ReferenceLinker_test.cpp @@ -317,12 +317,12 @@ TEST(ReferenceLinkerTest, ReferenceWithNoPackageUsesCallSitePackage) { CallSite{"com.app.test"}, context.get(), &table); ASSERT_THAT(s, NotNull()); - EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x7f010000))); + EXPECT_THAT(s->id, Eq(0x7f010000)); s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"), CallSite{"com.app.lib"}, context.get(), &table); ASSERT_THAT(s, NotNull()); - EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x7f010001))); + EXPECT_THAT(s->id, Eq(0x7f010001)); EXPECT_THAT(ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"), CallSite{"com.app.bad"}, context.get(), &table), @@ -348,7 +348,7 @@ TEST(ReferenceLinkerTest, ReferenceSymbolFromOtherSplit) { CallSite{"com.app.test"}, context.get(), &table); ASSERT_THAT(s, NotNull()); - EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x80010000))); + EXPECT_THAT(s->id, Eq(0x80010000)); s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"), CallSite{"com.app.lib"}, context.get(), &table); diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp index 22f4d18dc3ca..d094d3619020 100644 --- a/tools/aapt2/link/TableMerger.cpp +++ b/tools/aapt2/link/TableMerger.cpp @@ -303,8 +303,8 @@ bool TableMerger::DoMerge(const Source& src, ResourceTablePackage* src_package, dst_config_value->value = std::move(new_file_ref); } else { - Maybe<std::string> original_comment = (dst_config_value->value) - ? dst_config_value->value->GetComment() : Maybe<std::string>(); + auto original_comment = (dst_config_value->value) + ? dst_config_value->value->GetComment() : std::optional<std::string>(); dst_config_value->value = src_config_value->value->Transform(cloner); diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp index 4358fb565a7d..4cbf2d3a826c 100644 --- a/tools/aapt2/link/TableMerger_test.cpp +++ b/tools/aapt2/link/TableMerger_test.cpp @@ -409,8 +409,7 @@ TEST_F(TableMergerTest, OverlaidStyleablesAndStylesShouldBeMerged) { const auto expected = ResourceUtils::MakeBool(true); EXPECT_THAT(style->entries, Contains(Field(&Style::Entry::value, Pointee(ValueEq(*expected))))); - EXPECT_THAT(style->parent, - Eq(make_value(Reference(test::ParseNameOrDie("com.app.a:style/OverlayParent"))))); + EXPECT_THAT(style->parent, Reference(test::ParseNameOrDie("com.app.a:style/OverlayParent"))); } TEST_F(TableMergerTest, OverrideStyleInsteadOfOverlaying) { @@ -483,7 +482,7 @@ TEST_F(TableMergerTest, SetOverlayable) { ASSERT_TRUE(merger.Merge({}, table_b.get(), false /*overlay*/)); const ResourceName name = test::ParseNameOrDie("com.app.a:bool/foo"); - Maybe<ResourceTable::SearchResult> search_result = final_table.FindResource(name); + std::optional<ResourceTable::SearchResult> search_result = final_table.FindResource(name); ASSERT_TRUE(search_result); ASSERT_TRUE(search_result.value().entry->overlayable_item); OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value(); @@ -517,7 +516,7 @@ TEST_F(TableMergerTest, SetOverlayableLater) { ASSERT_TRUE(merger.Merge({}, table_b.get(), false /*overlay*/)); const ResourceName name = test::ParseNameOrDie("com.app.a:bool/foo"); - Maybe<ResourceTable::SearchResult> search_result = final_table.FindResource(name); + std::optional<ResourceTable::SearchResult> search_result = final_table.FindResource(name); ASSERT_TRUE(search_result); ASSERT_TRUE(search_result.value().entry->overlayable_item); OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value(); diff --git a/tools/aapt2/link/XmlReferenceLinker.cpp b/tools/aapt2/link/XmlReferenceLinker.cpp index aaa085e2eb15..1f8548b5de75 100644 --- a/tools/aapt2/link/XmlReferenceLinker.cpp +++ b/tools/aapt2/link/XmlReferenceLinker.cpp @@ -68,7 +68,7 @@ class XmlVisitor : public xml::PackageAwareVisitor { const Attribute* attribute = &default_attribute; - if (Maybe<xml::ExtractedPackage> maybe_package = + if (std::optional<xml::ExtractedPackage> maybe_package = xml::ExtractPackageFromNamespace(attr.namespace_uri)) { // There is a valid package name for this attribute. We will look this up. Reference attr_ref( diff --git a/tools/aapt2/link/XmlReferenceLinker_test.cpp b/tools/aapt2/link/XmlReferenceLinker_test.cpp index ddf5b9a22c2f..6d96cf1cf502 100644 --- a/tools/aapt2/link/XmlReferenceLinker_test.cpp +++ b/tools/aapt2/link/XmlReferenceLinker_test.cpp @@ -100,18 +100,18 @@ TEST_F(XmlReferenceLinkerTest, LinkBasicAttributes) { xml::Attribute* xml_attr = view_el->FindAttribute(xml::kSchemaAndroid, "layout_width"); ASSERT_THAT(xml_attr, NotNull()); ASSERT_TRUE(xml_attr->compiled_attribute); - EXPECT_EQ(make_value(ResourceId(0x01010000)), xml_attr->compiled_attribute.value().id); + EXPECT_EQ(ResourceId(0x01010000), xml_attr->compiled_attribute.value().id); EXPECT_THAT(ValueCast<BinaryPrimitive>(xml_attr->compiled_value.get()), NotNull()); xml_attr = view_el->FindAttribute(xml::kSchemaAndroid, "background"); ASSERT_THAT(xml_attr, NotNull()); ASSERT_TRUE(xml_attr->compiled_attribute); - EXPECT_EQ(make_value(ResourceId(0x01010001)), xml_attr->compiled_attribute.value().id); + EXPECT_EQ(ResourceId(0x01010001), xml_attr->compiled_attribute.value().id); Reference* ref = ValueCast<Reference>(xml_attr->compiled_value.get()); ASSERT_THAT(ref, NotNull()); - EXPECT_EQ(make_value(test::ParseNameOrDie("color/green")), ref->name); // Make sure the name - // didn't change. - EXPECT_EQ(make_value(ResourceId(0x7f020000)), ref->id); + EXPECT_EQ(test::ParseNameOrDie("color/green"), ref->name); // Make sure the name + // didn't change. + EXPECT_EQ(ResourceId(0x7f020000), ref->id); xml_attr = view_el->FindAttribute(xml::kSchemaAndroid, "text"); ASSERT_THAT(xml_attr, NotNull()); @@ -172,7 +172,7 @@ TEST_F(XmlReferenceLinkerTest, LinkMangledAttributes) { view_el->FindAttribute(xml::BuildPackageNamespace("com.android.support"), "colorAccent"); ASSERT_THAT(xml_attr, NotNull()); ASSERT_TRUE(xml_attr->compiled_attribute); - EXPECT_EQ(make_value(ResourceId(0x7f010001)), xml_attr->compiled_attribute.value().id); + EXPECT_EQ(ResourceId(0x7f010001), xml_attr->compiled_attribute.value().id); EXPECT_THAT(ValueCast<BinaryPrimitive>(xml_attr->compiled_value.get()), NotNull()); } @@ -190,11 +190,11 @@ TEST_F(XmlReferenceLinkerTest, LinkAutoResReference) { xml::Attribute* xml_attr = view_el->FindAttribute(xml::kSchemaAuto, "colorAccent"); ASSERT_THAT(xml_attr, NotNull()); ASSERT_TRUE(xml_attr->compiled_attribute); - EXPECT_EQ(make_value(ResourceId(0x7f010000)), xml_attr->compiled_attribute.value().id); + EXPECT_EQ(ResourceId(0x7f010000), xml_attr->compiled_attribute.value().id); Reference* ref = ValueCast<Reference>(xml_attr->compiled_value.get()); ASSERT_THAT(ref, NotNull()); ASSERT_TRUE(ref->name); - EXPECT_EQ(make_value(ResourceId(0x7f020001)), ref->id); + EXPECT_EQ(ResourceId(0x7f020001), ref->id); } TEST_F(XmlReferenceLinkerTest, LinkViewWithShadowedPackageAlias) { @@ -214,10 +214,10 @@ TEST_F(XmlReferenceLinkerTest, LinkViewWithShadowedPackageAlias) { xml::Attribute* xml_attr = view_el->FindAttribute(xml::kSchemaAndroid, "attr"); ASSERT_THAT(xml_attr, NotNull()); ASSERT_TRUE(xml_attr->compiled_attribute); - EXPECT_EQ(make_value(ResourceId(0x01010002)), xml_attr->compiled_attribute.value().id); + EXPECT_EQ(ResourceId(0x01010002), xml_attr->compiled_attribute.value().id); Reference* ref = ValueCast<Reference>(xml_attr->compiled_value.get()); ASSERT_THAT(ref, NotNull()); - EXPECT_EQ(make_value(ResourceId(0x01030000)), ref->id); + EXPECT_EQ(ResourceId(0x01030000), ref->id); ASSERT_FALSE(view_el->GetChildElements().empty()); view_el = view_el->GetChildElements().front(); @@ -228,10 +228,10 @@ TEST_F(XmlReferenceLinkerTest, LinkViewWithShadowedPackageAlias) { xml_attr = view_el->FindAttribute(xml::BuildPackageNamespace("com.app.test"), "attr"); ASSERT_THAT(xml_attr, NotNull()); ASSERT_TRUE(xml_attr->compiled_attribute); - EXPECT_EQ(make_value(ResourceId(0x7f010002)), xml_attr->compiled_attribute.value().id); + EXPECT_EQ(ResourceId(0x7f010002), xml_attr->compiled_attribute.value().id); ref = ValueCast<Reference>(xml_attr->compiled_value.get()); ASSERT_THAT(ref, NotNull()); - EXPECT_EQ(make_value(ResourceId(0x7f030000)), ref->id); + EXPECT_EQ(ResourceId(0x7f030000), ref->id); } TEST_F(XmlReferenceLinkerTest, LinkViewWithLocalPackageAndAliasOfTheSameName) { @@ -250,10 +250,10 @@ TEST_F(XmlReferenceLinkerTest, LinkViewWithLocalPackageAndAliasOfTheSameName) { xml::Attribute* xml_attr = view_el->FindAttribute(xml::BuildPackageNamespace("com.app.test"), "attr"); ASSERT_THAT(xml_attr, NotNull()); ASSERT_TRUE(xml_attr->compiled_attribute); - EXPECT_EQ(make_value(ResourceId(0x7f010002)), xml_attr->compiled_attribute.value().id); + EXPECT_EQ(ResourceId(0x7f010002), xml_attr->compiled_attribute.value().id); Reference* ref = ValueCast<Reference>(xml_attr->compiled_value.get()); ASSERT_THAT(ref, NotNull()); - EXPECT_EQ(make_value(ResourceId(0x7f030000)), ref->id); + EXPECT_EQ(ResourceId(0x7f030000), ref->id); } @@ -270,7 +270,7 @@ TEST_F(XmlReferenceLinkerTest, AddAngleOnGradientForAndroidQ) { xml::Attribute* xml_attr = gradient_el->FindAttribute(xml::kSchemaAndroid, "angle"); ASSERT_THAT(xml_attr, NotNull()); ASSERT_TRUE(xml_attr->compiled_attribute); - EXPECT_EQ(make_value(ResourceId(0x01010004)), xml_attr->compiled_attribute.value().id); + EXPECT_EQ(ResourceId(0x01010004), xml_attr->compiled_attribute.value().id); BinaryPrimitive* value = ValueCast<BinaryPrimitive>(xml_attr->compiled_value.get()); ASSERT_THAT(value, NotNull()); @@ -292,7 +292,7 @@ TEST_F(XmlReferenceLinkerTest, DoNotOverwriteAngleOnGradientForAndroidQ) { xml::Attribute* xml_attr = gradient_el->FindAttribute(xml::kSchemaAndroid, "angle"); ASSERT_THAT(xml_attr, NotNull()); ASSERT_TRUE(xml_attr->compiled_attribute); - EXPECT_EQ(make_value(ResourceId(0x01010004)), xml_attr->compiled_attribute.value().id); + EXPECT_EQ(ResourceId(0x01010004), xml_attr->compiled_attribute.value().id); BinaryPrimitive* value = ValueCast<BinaryPrimitive>(xml_attr->compiled_value.get()); ASSERT_THAT(value, NotNull()); diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp index d385267fe5ed..2d58cbfb3dbe 100644 --- a/tools/aapt2/process/SymbolTable.cpp +++ b/tools/aapt2/process/SymbolTable.cpp @@ -75,8 +75,8 @@ const SymbolTable::Symbol* SymbolTable::FindByName(const ResourceName& name) { // Fill in the package name if necessary. // If there is no package in `name`, we will need to copy the ResourceName - // and store it somewhere; we use the Maybe<> class to reserve storage. - Maybe<ResourceName> name_with_package_impl; + // and store it somewhere; we use the std::optional<> class to reserve storage. + std::optional<ResourceName> name_with_package_impl; if (name.package.empty()) { name_with_package_impl = ResourceName(mangler_->GetTargetPackageName(), name.type, name.entry); name_with_package = &name_with_package_impl.value(); @@ -88,9 +88,9 @@ const SymbolTable::Symbol* SymbolTable::FindByName(const ResourceName& name) { } // The name was not found in the cache. Mangle it (if necessary) and find it in our sources. - // Again, here we use a Maybe<> object to reserve storage if we need to mangle. + // Again, here we use a std::optional<> object to reserve storage if we need to mangle. const ResourceName* mangled_name = name_with_package; - Maybe<ResourceName> mangled_name_impl; + std::optional<ResourceName> mangled_name_impl; if (mangler_->ShouldMangle(name_with_package->package)) { mangled_name_impl = mangler_->MangleName(*name_with_package); mangled_name = &mangled_name_impl.value(); @@ -183,7 +183,7 @@ std::unique_ptr<SymbolTable::Symbol> DefaultSymbolTableDelegate::FindById( std::unique_ptr<SymbolTable::Symbol> ResourceTableSymbolSource::FindByName( const ResourceName& name) { - Maybe<ResourceTable::SearchResult> result = table_->FindResource(name); + std::optional<ResourceTable::SearchResult> result = table_->FindResource(name); if (!result) { if (name.type == ResourceType::kAttr) { // Recurse and try looking up a private attribute. @@ -306,7 +306,7 @@ static std::unique_ptr<SymbolTable::Symbol> LookupAttributeInTable( return nullptr; } - Maybe<ResourceName> parsed_name = ResourceUtils::ToResourceName(*name); + std::optional<ResourceName> parsed_name = ResourceUtils::ToResourceName(*name); if (!parsed_name) { return nullptr; } @@ -382,8 +382,7 @@ std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindByName( return {}; } -static Maybe<ResourceName> GetResourceName(android::AssetManager2& am, - ResourceId id) { +static std::optional<ResourceName> GetResourceName(android::AssetManager2& am, ResourceId id) { auto name = am.GetResourceName(id.id); if (!name.has_value()) { return {}; @@ -402,7 +401,7 @@ std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindById( return {}; } - Maybe<ResourceName> maybe_name = GetResourceName(asset_manager_, id); + std::optional<ResourceName> maybe_name = GetResourceName(asset_manager_, id); if (!maybe_name) { return {}; } diff --git a/tools/aapt2/process/SymbolTable.h b/tools/aapt2/process/SymbolTable.h index 06eaf63ad442..65ae7beadc07 100644 --- a/tools/aapt2/process/SymbolTable.h +++ b/tools/aapt2/process/SymbolTable.h @@ -56,7 +56,7 @@ class SymbolTable { struct Symbol { Symbol() = default; - explicit Symbol(const Maybe<ResourceId>& i, const std::shared_ptr<Attribute>& attr = {}, + explicit Symbol(const std::optional<ResourceId>& i, const std::shared_ptr<Attribute>& attr = {}, bool pub = false) : id(i), attribute(attr), is_public(pub) { } @@ -66,7 +66,7 @@ class SymbolTable { Symbol& operator=(const Symbol&) = default; Symbol& operator=(Symbol&&) = default; - Maybe<ResourceId> id; + std::optional<ResourceId> id; std::shared_ptr<Attribute> attribute; bool is_public = false; bool is_dynamic = false; diff --git a/tools/aapt2/test/Builders.cpp b/tools/aapt2/test/Builders.cpp index 4816596da487..23331de02df7 100644 --- a/tools/aapt2/test/Builders.cpp +++ b/tools/aapt2/test/Builders.cpp @@ -159,7 +159,8 @@ std::unique_ptr<ResourceTable> ResourceTableBuilder::Build() { return std::move(table_); } -std::unique_ptr<Reference> BuildReference(const StringPiece& ref, const Maybe<ResourceId>& id) { +std::unique_ptr<Reference> BuildReference(const StringPiece& ref, + const std::optional<ResourceId>& id) { std::unique_ptr<Reference> reference = util::make_unique<Reference>(ParseNameOrDie(ref)); reference->id = id; return reference; @@ -218,7 +219,8 @@ std::unique_ptr<Style> StyleBuilder::Build() { return std::move(style_); } -StyleableBuilder& StyleableBuilder::AddItem(const StringPiece& str, const Maybe<ResourceId>& id) { +StyleableBuilder& StyleableBuilder::AddItem(const StringPiece& str, + const std::optional<ResourceId>& id) { styleable_->entries.push_back(Reference(ParseNameOrDie(str))); styleable_->entries.back().id = id; return *this; diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h index 3ff955d65f24..55778aea40af 100644 --- a/tools/aapt2/test/Builders.h +++ b/tools/aapt2/test/Builders.h @@ -29,7 +29,6 @@ #include "configuration/ConfigurationParser.internal.h" #include "process/IResourceTableConsumer.h" #include "test/Common.h" -#include "util/Maybe.h" #include "xml/XmlDom.h" namespace aapt { @@ -86,7 +85,7 @@ class ResourceTableBuilder { }; std::unique_ptr<Reference> BuildReference(const android::StringPiece& ref, - const Maybe<ResourceId>& id = {}); + const std::optional<ResourceId>& id = {}); std::unique_ptr<BinaryPrimitive> BuildPrimitive(uint8_t type, uint32_t data); template <typename T> @@ -149,7 +148,8 @@ class StyleBuilder { class StyleableBuilder { public: StyleableBuilder() = default; - StyleableBuilder& AddItem(const android::StringPiece& str, const Maybe<ResourceId>& id = {}); + StyleableBuilder& AddItem(const android::StringPiece& str, + const std::optional<ResourceId>& id = {}); std::unique_ptr<Styleable> Build(); private: diff --git a/tools/aapt2/test/Common.cpp b/tools/aapt2/test/Common.cpp index 23c22185a53f..e029d025b366 100644 --- a/tools/aapt2/test/Common.cpp +++ b/tools/aapt2/test/Common.cpp @@ -48,7 +48,7 @@ Value* GetValueForConfigAndProduct<Value>(ResourceTable* table, const android::StringPiece& res_name, const ConfigDescription& config, const android::StringPiece& product) { - Maybe<ResourceTable::SearchResult> result = table->FindResource(ParseNameOrDie(res_name)); + std::optional<ResourceTable::SearchResult> result = table->FindResource(ParseNameOrDie(res_name)); if (result) { ResourceConfigValue* config_value = result.value().entry->FindValue(config, product); if (config_value) { diff --git a/tools/aapt2/test/Common.h b/tools/aapt2/test/Common.h index 777ca5c72619..7006964d6f88 100644 --- a/tools/aapt2/test/Common.h +++ b/tools/aapt2/test/Common.h @@ -55,7 +55,7 @@ template <typename T = Value> T* GetValueForConfigAndProduct(ResourceTable* table, const android::StringPiece& res_name, const android::ConfigDescription& config, const android::StringPiece& product) { - Maybe<ResourceTable::SearchResult> result = table->FindResource(ParseNameOrDie(res_name)); + std::optional<ResourceTable::SearchResult> result = table->FindResource(ParseNameOrDie(res_name)); if (result) { ResourceConfigValue* config_value = result.value().entry->FindValue(config, product); if (config_value) { @@ -130,7 +130,7 @@ template std::ostream& operator<<<Plural>(std::ostream&, const Plural&); // Add a print method to Maybe. template <typename T> -void PrintTo(const Maybe<T>& value, std::ostream* out) { +void PrintTo(const std::optional<T>& value, std::ostream* out) { if (value) { *out << ::testing::PrintToString(value.value()); } else { diff --git a/tools/aapt2/test/Context.h b/tools/aapt2/test/Context.h index 5d8ded39e654..e1b8dd5687ff 100644 --- a/tools/aapt2/test/Context.h +++ b/tools/aapt2/test/Context.h @@ -95,8 +95,8 @@ class Context : public IAaptContext { friend class ContextBuilder; PackageType package_type_ = PackageType::kApp; - Maybe<std::string> compilation_package_; - Maybe<uint8_t> package_id_; + std::optional<std::string> compilation_package_; + std::optional<uint8_t> package_id_; StdErrDiagnostics diagnostics_; NameMangler name_mangler_; SymbolTable symbols_; diff --git a/tools/aapt2/test/Fixture.cpp b/tools/aapt2/test/Fixture.cpp index 285e5a11b4c0..e2f71dc45075 100644 --- a/tools/aapt2/test/Fixture.cpp +++ b/tools/aapt2/test/Fixture.cpp @@ -126,7 +126,7 @@ bool CommandTestFixture::Link(const std::vector<std::string>& args, link_args.insert(link_args.end(), {"-I", android_sdk}); // Add the files from the compiled resources directory to the link file arguments - Maybe<std::vector<std::string>> compiled_files = file::FindFiles(flat_dir, diag); + std::optional<std::vector<std::string>> compiled_files = file::FindFiles(flat_dir, diag); if (compiled_files) { for (std::string& compile_file : compiled_files.value()) { compile_file = file::BuildPath({flat_dir, compile_file}); diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp index 5d57de6a9fb1..5d2eda3293f0 100644 --- a/tools/aapt2/util/Files.cpp +++ b/tools/aapt2/util/Files.cpp @@ -50,12 +50,12 @@ namespace file { FileType GetFileType(const std::string& path) { std::wstring path_utf16; if (!::android::base::UTF8PathToWindowsLongPath(path.c_str(), &path_utf16)) { - return FileType::kNonexistant; + return FileType::kNonExistant; } DWORD result = GetFileAttributesW(path_utf16.c_str()); if (result == INVALID_FILE_ATTRIBUTES) { - return FileType::kNonexistant; + return FileType::kNonExistant; } if (result & FILE_ATTRIBUTE_DIRECTORY) { @@ -72,7 +72,7 @@ FileType GetFileType(const std::string& path) { if (result == -1) { if (errno == ENOENT || errno == ENOTDIR) { - return FileType::kNonexistant; + return FileType::kNonExistant; } return FileType::kUnknown; } @@ -208,7 +208,7 @@ std::string PackageToPath(const StringPiece& package) { return out_path; } -Maybe<FileMap> MmapPath(const std::string& path, std::string* out_error) { +std::optional<FileMap> MmapPath(const std::string& path, std::string* out_error) { int flags = O_RDONLY | O_CLOEXEC | O_BINARY; unique_fd fd(TEMP_FAILURE_RETRY(::android::base::utf8::open(path.c_str(), flags))); if (fd == -1) { @@ -344,8 +344,8 @@ bool FileFilter::operator()(const std::string& filename, FileType type) const { return true; } -Maybe<std::vector<std::string>> FindFiles(const android::StringPiece& path, IDiagnostics* diag, - const FileFilter* filter) { +std::optional<std::vector<std::string>> FindFiles(const android::StringPiece& path, + IDiagnostics* diag, const FileFilter* filter) { const std::string root_dir = path.to_string(); std::unique_ptr<DIR, decltype(closedir)*> d(opendir(root_dir.data()), closedir); if (!d) { @@ -382,7 +382,7 @@ Maybe<std::vector<std::string>> FindFiles(const android::StringPiece& path, IDia for (const std::string& subdir : subdirs) { std::string full_subdir = root_dir; AppendPath(&full_subdir, subdir); - Maybe<std::vector<std::string>> subfiles = FindFiles(full_subdir, diag, filter); + std::optional<std::vector<std::string>> subfiles = FindFiles(full_subdir, diag, filter); if (!subfiles) { return {}; } diff --git a/tools/aapt2/util/Files.h b/tools/aapt2/util/Files.h index 481a4cdb6ad0..877cd56d6c69 100644 --- a/tools/aapt2/util/Files.h +++ b/tools/aapt2/util/Files.h @@ -18,6 +18,7 @@ #define AAPT_FILES_H #include <memory> +#include <optional> #include <string> #include <unordered_set> #include <vector> @@ -27,7 +28,6 @@ #include "utils/FileMap.h" #include "Diagnostics.h" -#include "Maybe.h" #include "Source.h" namespace aapt { @@ -43,7 +43,7 @@ constexpr const char sPathSep = ':'; enum class FileType { kUnknown = 0, - kNonexistant, + kNonExistant, kRegular, kDirectory, kCharDev, @@ -81,7 +81,7 @@ bool IsHidden(const android::StringPiece& path); std::string PackageToPath(const android::StringPiece& package); // Creates a FileMap for the file at path. -Maybe<android::FileMap> MmapPath(const std::string& path, std::string* out_error); +std::optional<android::FileMap> MmapPath(const std::string& path, std::string* out_error); // Reads the file at path and appends each line to the outArgList vector. bool AppendArgsFromFile(const android::StringPiece& path, std::vector<std::string>* out_arglist, @@ -124,8 +124,9 @@ class FileFilter { // Returns a list of files relative to the directory identified by `path`. // An optional FileFilter filters out any files that don't pass. -Maybe<std::vector<std::string>> FindFiles(const android::StringPiece& path, IDiagnostics* diag, - const FileFilter* filter = nullptr); +std::optional<std::vector<std::string>> FindFiles(const android::StringPiece& path, + IDiagnostics* diag, + const FileFilter* filter = nullptr); } // namespace file } // namespace aapt diff --git a/tools/aapt2/util/Maybe.h b/tools/aapt2/util/Maybe.h deleted file mode 100644 index 047e1a581330..000000000000 --- a/tools/aapt2/util/Maybe.h +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#ifndef AAPT_MAYBE_H -#define AAPT_MAYBE_H - -#include <type_traits> -#include <utility> - -#include "android-base/logging.h" - -#include "util/TypeTraits.h" - -namespace aapt { - -/** - * Either holds a valid value of type T, or holds Nothing. - * The value is stored inline in this structure, so no - * heap memory is used when creating a Maybe<T> object. - */ -template <typename T> -class Maybe { - public: - /** - * Construct Nothing. - */ - Maybe(); - - ~Maybe(); - - Maybe(const Maybe& rhs); - - template <typename U> - Maybe(const Maybe<U>& rhs); // NOLINT(google-explicit-constructor) - - Maybe(Maybe&& rhs) noexcept; - - template <typename U> - Maybe(Maybe<U>&& rhs); // NOLINT(google-explicit-constructor) - - Maybe& operator=(const Maybe& rhs); - - template <typename U> - Maybe& operator=(const Maybe<U>& rhs); - - Maybe& operator=(Maybe&& rhs) noexcept; - - template <typename U> - Maybe& operator=(Maybe<U>&& rhs); - - /** - * Construct a Maybe holding a value. - */ - Maybe(const T& value); // NOLINT(google-explicit-constructor) - - /** - * Construct a Maybe holding a value. - */ - Maybe(T&& value); // NOLINT(google-explicit-constructor) - - /** - * True if this holds a value, false if - * it holds Nothing. - */ - explicit operator bool() const; - - /** - * Gets the value if one exists, or else - * panics. - */ - T& value(); - - /** - * Gets the value if one exists, or else - * panics. - */ - const T& value() const; - - T value_or_default(const T& def) const; - - private: - template <typename U> - friend class Maybe; - - template <typename U> - Maybe& copy(const Maybe<U>& rhs); - - template <typename U> - Maybe& move(Maybe<U>&& rhs); - - void destroy(); - - bool nothing_; - - typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_; -}; - -template <typename T> -Maybe<T>::Maybe() : nothing_(true) {} - -template <typename T> -Maybe<T>::~Maybe() { - if (!nothing_) { - destroy(); - } -} - -template <typename T> -Maybe<T>::Maybe(const Maybe& rhs) : nothing_(rhs.nothing_) { - if (!rhs.nothing_) { - new (&storage_) T(reinterpret_cast<const T&>(rhs.storage_)); - } -} - -template <typename T> -template <typename U> -Maybe<T>::Maybe(const Maybe<U>& rhs) : nothing_(rhs.nothing_) { - if (!rhs.nothing_) { - new (&storage_) T(reinterpret_cast<const U&>(rhs.storage_)); - } -} - -template <typename T> -Maybe<T>::Maybe(Maybe&& rhs) noexcept : nothing_(rhs.nothing_) { - if (!rhs.nothing_) { - rhs.nothing_ = true; - - // Move the value from rhs. - new (&storage_) T(std::move(reinterpret_cast<T&>(rhs.storage_))); - rhs.destroy(); - } -} - -template <typename T> -template <typename U> -Maybe<T>::Maybe(Maybe<U>&& rhs) : nothing_(rhs.nothing_) { - if (!rhs.nothing_) { - rhs.nothing_ = true; - - // Move the value from rhs. - new (&storage_) T(std::move(reinterpret_cast<U&>(rhs.storage_))); - rhs.destroy(); - } -} - -template <typename T> -inline Maybe<T>& Maybe<T>::operator=(const Maybe& rhs) { - // Delegate to the actual assignment. - return copy(rhs); -} - -template <typename T> -template <typename U> -inline Maybe<T>& Maybe<T>::operator=(const Maybe<U>& rhs) { - return copy(rhs); -} - -template <typename T> -template <typename U> -Maybe<T>& Maybe<T>::copy(const Maybe<U>& rhs) { - if (nothing_ && rhs.nothing_) { - // Both are nothing, nothing to do. - return *this; - } else if (!nothing_ && !rhs.nothing_) { - // We both are something, so assign rhs to us. - reinterpret_cast<T&>(storage_) = reinterpret_cast<const U&>(rhs.storage_); - } else if (nothing_) { - // We are nothing but rhs is something. - nothing_ = rhs.nothing_; - - // Copy the value from rhs. - new (&storage_) T(reinterpret_cast<const U&>(rhs.storage_)); - } else { - // We are something but rhs is nothing, so destroy our value. - nothing_ = rhs.nothing_; - destroy(); - } - return *this; -} - -template <typename T> -inline Maybe<T>& Maybe<T>::operator=(Maybe&& rhs) noexcept { - // Delegate to the actual assignment. - return move(std::forward<Maybe<T>>(rhs)); -} - -template <typename T> -template <typename U> -inline Maybe<T>& Maybe<T>::operator=(Maybe<U>&& rhs) { - return move(std::forward<Maybe<U>>(rhs)); -} - -template <typename T> -template <typename U> -Maybe<T>& Maybe<T>::move(Maybe<U>&& rhs) { - if (nothing_ && rhs.nothing_) { - // Both are nothing, nothing to do. - return *this; - } else if (!nothing_ && !rhs.nothing_) { - // We both are something, so move assign rhs to us. - rhs.nothing_ = true; - reinterpret_cast<T&>(storage_) = - std::move(reinterpret_cast<U&>(rhs.storage_)); - rhs.destroy(); - } else if (nothing_) { - // We are nothing but rhs is something. - nothing_ = false; - rhs.nothing_ = true; - - // Move the value from rhs. - new (&storage_) T(std::move(reinterpret_cast<U&>(rhs.storage_))); - rhs.destroy(); - } else { - // We are something but rhs is nothing, so destroy our value. - nothing_ = true; - destroy(); - } - return *this; -} - -template <typename T> -Maybe<T>::Maybe(const T& value) : nothing_(false) { - new (&storage_) T(value); -} - -template <typename T> -Maybe<T>::Maybe(T&& value) : nothing_(false) { - new (&storage_) T(std::forward<T>(value)); -} - -template <typename T> -Maybe<T>::operator bool() const { - return !nothing_; -} - -template <typename T> -T& Maybe<T>::value() { - CHECK(!nothing_) << "Maybe<T>::value() called on Nothing"; - return reinterpret_cast<T&>(storage_); -} - -template <typename T> -const T& Maybe<T>::value() const { - CHECK(!nothing_) << "Maybe<T>::value() called on Nothing"; - return reinterpret_cast<const T&>(storage_); -} - -template <typename T> -T Maybe<T>::value_or_default(const T& def) const { - if (nothing_) { - return def; - } - return reinterpret_cast<const T&>(storage_); -} - -template <typename T> -void Maybe<T>::destroy() { - reinterpret_cast<T&>(storage_).~T(); -} - -template <typename T> -inline Maybe<typename std::remove_reference<T>::type> make_value(T&& value) { - return Maybe<typename std::remove_reference<T>::type>(std::forward<T>(value)); -} - -template <typename T> -inline Maybe<T> make_nothing() { - return Maybe<T>(); -} - -// Define the == operator between Maybe<T> and Maybe<U> only if the operator T == U is defined. -// That way the compiler will show an error at the callsite when comparing two Maybe<> objects -// whose inner types can't be compared. -template <typename T, typename U> -typename std::enable_if<has_eq_op<T, U>::value, bool>::type operator==(const Maybe<T>& a, - const Maybe<U>& b) { - if (a && b) { - return a.value() == b.value(); - } else if (!a && !b) { - return true; - } - return false; -} - -template <typename T, typename U> -typename std::enable_if<has_eq_op<T, U>::value, bool>::type operator==(const Maybe<T>& a, - const U& b) { - return a ? a.value() == b : false; -} - -// Same as operator== but negated. -template <typename T, typename U> -typename std::enable_if<has_eq_op<T, U>::value, bool>::type operator!=(const Maybe<T>& a, - const Maybe<U>& b) { - return !(a == b); -} - -template <typename T, typename U> -typename std::enable_if<has_lt_op<T, U>::value, bool>::type operator<(const Maybe<T>& a, - const Maybe<U>& b) { - if (a && b) { - return a.value() < b.value(); - } else if (!a && !b) { - return false; - } - return !a; -} - -} // namespace aapt - -#endif // AAPT_MAYBE_H diff --git a/tools/aapt2/util/Maybe_test.cpp b/tools/aapt2/util/Maybe_test.cpp deleted file mode 100644 index 4c921f13a3ca..000000000000 --- a/tools/aapt2/util/Maybe_test.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "util/Maybe.h" - -#include <string> - -#include "test/Test.h" - -namespace aapt { - -struct Fake { - Fake() { - data = new int; - *data = 1; - std::cerr << "Construct Fake{0x" << (void*)this << "} with data=0x" - << (void*)data << std::endl; - } - - Fake(const Fake& rhs) { - data = nullptr; - if (rhs.data) { - data = new int; - *data = *rhs.data; - } - std::cerr << "CopyConstruct Fake{0x" << (void*)this << "} from Fake{0x" - << (const void*)&rhs << "}" << std::endl; - } - - Fake(Fake&& rhs) { - data = rhs.data; - rhs.data = nullptr; - std::cerr << "MoveConstruct Fake{0x" << (void*)this << "} from Fake{0x" - << (const void*)&rhs << "}" << std::endl; - } - - Fake& operator=(const Fake& rhs) { - delete data; - data = nullptr; - - if (rhs.data) { - data = new int; - *data = *rhs.data; - } - std::cerr << "CopyAssign Fake{0x" << (void*)this << "} from Fake{0x" - << (const void*)&rhs << "}" << std::endl; - return *this; - } - - Fake& operator=(Fake&& rhs) { - delete data; - data = rhs.data; - rhs.data = nullptr; - std::cerr << "MoveAssign Fake{0x" << (void*)this << "} from Fake{0x" - << (const void*)&rhs << "}" << std::endl; - return *this; - } - - ~Fake() { - std::cerr << "Destruct Fake{0x" << (void*)this << "} with data=0x" - << (void*)data << std::endl; - delete data; - } - - int* data; -}; - -TEST(MaybeTest, MakeNothing) { - Maybe<int> val = make_nothing<int>(); - EXPECT_FALSE(val); - - Maybe<std::string> val2 = make_nothing<std::string>(); - EXPECT_FALSE(val2); - - val2 = make_nothing<std::string>(); - EXPECT_FALSE(val2); -} - -TEST(MaybeTest, MakeSomething) { - Maybe<int> val = make_value(23); - ASSERT_TRUE(val); - EXPECT_EQ(23, val.value()); - - Maybe<std::string> val2 = make_value(std::string("hey")); - ASSERT_TRUE(val2); - EXPECT_EQ(std::string("hey"), val2.value()); -} - -TEST(MaybeTest, Lifecycle) { - Maybe<Fake> val = make_nothing<Fake>(); - - Maybe<Fake> val2 = make_value(Fake()); -} - -TEST(MaybeTest, MoveAssign) { - Maybe<Fake> val; - { - Maybe<Fake> val2 = Fake(); - val = std::move(val2); - } -} - -TEST(MaybeTest, Equality) { - Maybe<int> a = 1; - Maybe<int> b = 1; - Maybe<int> c; - - Maybe<int> emptyA, emptyB; - - EXPECT_EQ(a, b); - EXPECT_EQ(b, a); - EXPECT_NE(a, c); - EXPECT_EQ(emptyA, emptyB); -} - -} // namespace aapt diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp index d7a8e6fe6ada..44b4ec13b2f1 100644 --- a/tools/aapt2/util/Util.cpp +++ b/tools/aapt2/util/Util.cpp @@ -28,7 +28,6 @@ #include "text/Unicode.h" #include "text/Utf8Iterator.h" #include "util/BigBuffer.h" -#include "util/Maybe.h" #include "utils/Unicode.h" using ::aapt::text::Utf8Iterator; @@ -193,8 +192,8 @@ bool IsAndroidSplitName(const StringPiece& str) { return IsAndroidNameImpl(str) > 0; } -Maybe<std::string> GetFullyQualifiedClassName(const StringPiece& package, - const StringPiece& classname) { +std::optional<std::string> GetFullyQualifiedClassName(const StringPiece& package, + const StringPiece& classname) { if (classname.empty()) { return {}; } diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h index c77aca31a810..c3efe6a63feb 100644 --- a/tools/aapt2/util/Util.h +++ b/tools/aapt2/util/Util.h @@ -28,7 +28,6 @@ #include "utils/ByteOrder.h" #include "util/BigBuffer.h" -#include "util/Maybe.h" #ifdef _WIN32 // TODO(adamlesinski): remove once http://b/32447322 is resolved. @@ -105,8 +104,8 @@ bool IsAndroidSharedUserId(const android::StringPiece& package_name, // .asdf --> package.asdf // .a.b --> package.a.b // asdf.adsf --> asdf.adsf -Maybe<std::string> GetFullyQualifiedClassName(const android::StringPiece& package, - const android::StringPiece& class_name); +std::optional<std::string> GetFullyQualifiedClassName(const android::StringPiece& package, + const android::StringPiece& class_name); // Retrieves the formatted name of aapt2. const char* GetToolName(); diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp index 2cdcfe45b50e..8b7eadf9fac9 100644 --- a/tools/aapt2/xml/XmlDom.cpp +++ b/tools/aapt2/xml/XmlDom.cpp @@ -545,7 +545,7 @@ void Text::Accept(ConstVisitor* visitor) const { void PackageAwareVisitor::BeforeVisitElement(Element* el) { std::vector<PackageDecl> decls; for (const NamespaceDecl& decl : el->namespace_decls) { - if (Maybe<ExtractedPackage> maybe_package = ExtractPackageFromNamespace(decl.uri)) { + if (std::optional<ExtractedPackage> maybe_package = ExtractPackageFromNamespace(decl.uri)) { decls.push_back(PackageDecl{decl.prefix, std::move(maybe_package.value())}); } } @@ -556,7 +556,8 @@ void PackageAwareVisitor::AfterVisitElement(Element* el) { package_decls_.pop_back(); } -Maybe<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias(const StringPiece& alias) const { +std::optional<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias( + const StringPiece& alias) const { if (alias.empty()) { return ExtractedPackage{{}, false /*private*/}; } diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h index a5b2d10fc9e0..5d31804d43b7 100644 --- a/tools/aapt2/xml/XmlDom.h +++ b/tools/aapt2/xml/XmlDom.h @@ -65,12 +65,12 @@ struct NamespaceDecl { }; struct AaptAttribute { - explicit AaptAttribute(const ::aapt::Attribute& attr, const Maybe<ResourceId>& resid = {}) + explicit AaptAttribute(const ::aapt::Attribute& attr, const std::optional<ResourceId>& resid = {}) : attribute(attr), id(resid) { } aapt::Attribute attribute; - Maybe<ResourceId> id; + std::optional<ResourceId> id; }; // An XML attribute. @@ -79,7 +79,7 @@ struct Attribute { std::string name; std::string value; - Maybe<AaptAttribute> compiled_attribute; + std::optional<AaptAttribute> compiled_attribute; std::unique_ptr<Item> compiled_value; }; @@ -235,7 +235,8 @@ class PackageAwareVisitor : public Visitor, public IPackageDeclStack { public: using Visitor::Visit; - Maybe<ExtractedPackage> TransformPackageAlias(const android::StringPiece& alias) const override; + std::optional<ExtractedPackage> TransformPackageAlias( + const android::StringPiece& alias) const override; protected: PackageAwareVisitor() = default; diff --git a/tools/aapt2/xml/XmlDom_test.cpp b/tools/aapt2/xml/XmlDom_test.cpp index ca46d539fe3c..6c717dcd84c8 100644 --- a/tools/aapt2/xml/XmlDom_test.cpp +++ b/tools/aapt2/xml/XmlDom_test.cpp @@ -98,7 +98,7 @@ TEST(XmlDomTest, BinaryInflate) { // the Attribute accepts (eg: string|reference). ASSERT_TRUE(new_doc->root->attributes[0].compiled_attribute); EXPECT_THAT(new_doc->root->attributes[0].compiled_attribute.value().id, - Eq(make_value(ResourceId(0x01010001u)))); + Eq(ResourceId(0x01010001u))); EXPECT_THAT(new_doc->root->attributes[0].value, StrEq("@string/foo")); EXPECT_THAT(new_doc->root->attributes[0].compiled_value, @@ -145,21 +145,19 @@ class TestVisitor : public PackageAwareVisitor { void Visit(Element* el) override { if (el->name == "View1") { - EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false}))); + EXPECT_THAT(TransformPackageAlias("one"), Eq(ExtractedPackage{"com.one", false})); } else if (el->name == "View2") { - EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false}))); - EXPECT_THAT(TransformPackageAlias("two"), Eq(make_value(ExtractedPackage{"com.two", false}))); + EXPECT_THAT(TransformPackageAlias("one"), Eq(ExtractedPackage{"com.one", false})); + EXPECT_THAT(TransformPackageAlias("two"), Eq(ExtractedPackage{"com.two", false})); } else if (el->name == "View3") { - EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false}))); - EXPECT_THAT(TransformPackageAlias("two"), Eq(make_value(ExtractedPackage{"com.two", false}))); - EXPECT_THAT(TransformPackageAlias("three"), - Eq(make_value(ExtractedPackage{"com.three", false}))); + EXPECT_THAT(TransformPackageAlias("one"), Eq(ExtractedPackage{"com.one", false})); + EXPECT_THAT(TransformPackageAlias("two"), Eq(ExtractedPackage{"com.two", false})); + EXPECT_THAT(TransformPackageAlias("three"), Eq(ExtractedPackage{"com.three", false})); } else if (el->name == "View4") { - EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false}))); - EXPECT_THAT(TransformPackageAlias("two"), Eq(make_value(ExtractedPackage{"com.two", false}))); - EXPECT_THAT(TransformPackageAlias("three"), - Eq(make_value(ExtractedPackage{"com.three", false}))); - EXPECT_THAT(TransformPackageAlias("four"), Eq(make_value(ExtractedPackage{"", true}))); + EXPECT_THAT(TransformPackageAlias("one"), Eq(ExtractedPackage{"com.one", false})); + EXPECT_THAT(TransformPackageAlias("two"), Eq(ExtractedPackage{"com.two", false})); + EXPECT_THAT(TransformPackageAlias("three"), Eq(ExtractedPackage{"com.three", false})); + EXPECT_THAT(TransformPackageAlias("four"), Eq(ExtractedPackage{"", true})); } } }; diff --git a/tools/aapt2/xml/XmlPullParser.cpp b/tools/aapt2/xml/XmlPullParser.cpp index 182203d397c3..bfa07490b9c0 100644 --- a/tools/aapt2/xml/XmlPullParser.cpp +++ b/tools/aapt2/xml/XmlPullParser.cpp @@ -17,7 +17,6 @@ #include <iostream> #include <string> -#include "util/Maybe.h" #include "util/Util.h" #include "xml/XmlPullParser.h" #include "xml/XmlUtil.h" @@ -84,8 +83,7 @@ XmlPullParser::Event XmlPullParser::Next() { // handling of references that use namespace aliases. if (next_event == Event::kStartNamespace || next_event == Event::kEndNamespace) { - Maybe<ExtractedPackage> result = - ExtractPackageFromNamespace(namespace_uri()); + std::optional<ExtractedPackage> result = ExtractPackageFromNamespace(namespace_uri()); if (next_event == Event::kStartNamespace) { if (result) { package_aliases_.emplace_back( @@ -142,7 +140,8 @@ const std::string& XmlPullParser::namespace_uri() const { return event_queue_.front().data2; } -Maybe<ExtractedPackage> XmlPullParser::TransformPackageAlias(const StringPiece& alias) const { +std::optional<ExtractedPackage> XmlPullParser::TransformPackageAlias( + const StringPiece& alias) const { if (alias.empty()) { return ExtractedPackage{{}, false /*private*/}; } @@ -308,8 +307,7 @@ void XMLCALL XmlPullParser::EndCdataSectionHandler(void* user_data) { parser->depth_ }); } -Maybe<StringPiece> FindAttribute(const XmlPullParser* parser, - const StringPiece& name) { +std::optional<StringPiece> FindAttribute(const XmlPullParser* parser, const StringPiece& name) { auto iter = parser->FindAttribute("", name); if (iter != parser->end_attributes()) { return StringPiece(util::TrimWhitespace(iter->value)); @@ -317,8 +315,8 @@ Maybe<StringPiece> FindAttribute(const XmlPullParser* parser, return {}; } -Maybe<StringPiece> FindNonEmptyAttribute(const XmlPullParser* parser, - const StringPiece& name) { +std::optional<StringPiece> FindNonEmptyAttribute(const XmlPullParser* parser, + const StringPiece& name) { auto iter = parser->FindAttribute("", name); if (iter != parser->end_attributes()) { StringPiece trimmed = util::TrimWhitespace(iter->value); diff --git a/tools/aapt2/xml/XmlPullParser.h b/tools/aapt2/xml/XmlPullParser.h index 5da2d4b10a4b..ab347728ae4b 100644 --- a/tools/aapt2/xml/XmlPullParser.h +++ b/tools/aapt2/xml/XmlPullParser.h @@ -33,7 +33,6 @@ #include "Resource.h" #include "io/Io.h" #include "process/IResourceTableConsumer.h" -#include "util/Maybe.h" #include "xml/XmlUtil.h" namespace aapt { @@ -121,7 +120,8 @@ class XmlPullParser : public IPackageDeclStack { * If xmlns:app="http://schemas.android.com/apk/res-auto", then * 'package' will be set to 'defaultPackage'. */ - Maybe<ExtractedPackage> TransformPackageAlias(const android::StringPiece& alias) const override; + std::optional<ExtractedPackage> TransformPackageAlias( + const android::StringPiece& alias) const override; struct PackageDecl { std::string prefix; @@ -193,16 +193,16 @@ class XmlPullParser : public IPackageDeclStack { /** * Finds the attribute in the current element within the global namespace. */ -Maybe<android::StringPiece> FindAttribute(const XmlPullParser* parser, - const android::StringPiece& name); +std::optional<android::StringPiece> FindAttribute(const XmlPullParser* parser, + const android::StringPiece& name); /** * Finds the attribute in the current element within the global namespace. The * attribute's value * must not be the empty string. */ -Maybe<android::StringPiece> FindNonEmptyAttribute(const XmlPullParser* parser, - const android::StringPiece& name); +std::optional<android::StringPiece> FindNonEmptyAttribute(const XmlPullParser* parser, + const android::StringPiece& name); // // Implementation diff --git a/tools/aapt2/xml/XmlUtil.cpp b/tools/aapt2/xml/XmlUtil.cpp index 0a622b2bd336..114b5ba7ab1a 100644 --- a/tools/aapt2/xml/XmlUtil.cpp +++ b/tools/aapt2/xml/XmlUtil.cpp @@ -19,7 +19,6 @@ #include <algorithm> #include <string> -#include "util/Maybe.h" #include "util/Util.h" #include "xml/XmlDom.h" @@ -34,8 +33,7 @@ std::string BuildPackageNamespace(const StringPiece& package, bool private_refer return result; } -Maybe<ExtractedPackage> ExtractPackageFromNamespace( - const std::string& namespace_uri) { +std::optional<ExtractedPackage> ExtractPackageFromNamespace(const std::string& namespace_uri) { if (util::StartsWith(namespace_uri, kSchemaPublicPrefix)) { StringPiece schema_prefix = kSchemaPublicPrefix; StringPiece package = namespace_uri; @@ -62,7 +60,7 @@ Maybe<ExtractedPackage> ExtractPackageFromNamespace( void ResolvePackage(const IPackageDeclStack* decl_stack, Reference* in_ref) { if (in_ref->name) { - if (Maybe<ExtractedPackage> transformed_package = + if (std::optional<ExtractedPackage> transformed_package = decl_stack->TransformPackageAlias(in_ref->name.value().package)) { ExtractedPackage& extracted_package = transformed_package.value(); in_ref->name.value().package = std::move(extracted_package.package); diff --git a/tools/aapt2/xml/XmlUtil.h b/tools/aapt2/xml/XmlUtil.h index 592a604f87a6..1ab05a93d314 100644 --- a/tools/aapt2/xml/XmlUtil.h +++ b/tools/aapt2/xml/XmlUtil.h @@ -20,7 +20,6 @@ #include <string> #include "ResourceValues.h" -#include "util/Maybe.h" namespace aapt { namespace xml { @@ -53,7 +52,7 @@ struct ExtractedPackage { // // Special case: if namespaceUri is http://schemas.android.com/apk/res-auto, returns an empty // package name. -Maybe<ExtractedPackage> ExtractPackageFromNamespace(const std::string& namespace_uri); +std::optional<ExtractedPackage> ExtractPackageFromNamespace(const std::string& namespace_uri); // Returns an XML Android namespace for the given package of the form: // http://schemas.android.com/apk/res/<package> @@ -69,7 +68,7 @@ struct IPackageDeclStack { virtual ~IPackageDeclStack() = default; // Returns an ExtractedPackage struct if the alias given corresponds with a package declaration. - virtual Maybe<ExtractedPackage> TransformPackageAlias( + virtual std::optional<ExtractedPackage> TransformPackageAlias( const android::StringPiece& alias) const = 0; }; diff --git a/tools/aapt2/xml/XmlUtil_test.cpp b/tools/aapt2/xml/XmlUtil_test.cpp index cbded8ffac8e..7b6ce9e96689 100644 --- a/tools/aapt2/xml/XmlUtil_test.cpp +++ b/tools/aapt2/xml/XmlUtil_test.cpp @@ -27,7 +27,7 @@ TEST(XmlUtilTest, ExtractPackageFromNamespace) { ASSERT_FALSE(xml::ExtractPackageFromNamespace("http://schemas.android.com/apk/res/")); ASSERT_FALSE(xml::ExtractPackageFromNamespace("http://schemas.android.com/apk/prv/res/")); - Maybe<xml::ExtractedPackage> p = + std::optional<xml::ExtractedPackage> p = xml::ExtractPackageFromNamespace("http://schemas.android.com/apk/res/a"); ASSERT_TRUE(p); EXPECT_EQ(std::string("a"), p.value().package); |