diff options
59 files changed, 2039 insertions, 531 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index b06374615730..815ccfe0b1c6 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -52022,6 +52022,7 @@ package android.view.accessibility { field public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 512; // 0x200 field public static final int CONTENT_CHANGE_TYPE_DRAG_DROPPED = 256; // 0x100 field public static final int CONTENT_CHANGE_TYPE_DRAG_STARTED = 128; // 0x80 + field public static final int CONTENT_CHANGE_TYPE_ENABLED = 4096; // 0x1000 field public static final int CONTENT_CHANGE_TYPE_ERROR = 2048; // 0x800 field public static final int CONTENT_CHANGE_TYPE_PANE_APPEARED = 16; // 0x10 field public static final int CONTENT_CHANGE_TYPE_PANE_DISAPPEARED = 32; // 0x20 diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 87960d70fa25..5e1c2347664b 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -7132,6 +7132,7 @@ package android.media.tv.tuner { field public static final int TUNER_VERSION_1_0 = 65536; // 0x10000 field public static final int TUNER_VERSION_1_1 = 65537; // 0x10001 field public static final int TUNER_VERSION_2_0 = 131072; // 0x20000 + field public static final int TUNER_VERSION_3_0 = 196608; // 0x30000 field public static final int TUNER_VERSION_UNKNOWN = 0; // 0x0 } @@ -7149,6 +7150,7 @@ package android.media.tv.tuner.dvr { method public long read(@NonNull byte[], long, long); method public long seek(long); method public void setFileDescriptor(@NonNull android.os.ParcelFileDescriptor); + method public int setPlaybackBufferStatusCheckIntervalHint(long); method public int start(); method public int stop(); field public static final int PLAYBACK_STATUS_ALMOST_EMPTY = 2; // 0x2 @@ -7164,6 +7166,7 @@ package android.media.tv.tuner.dvr { method public int detachFilter(@NonNull android.media.tv.tuner.filter.Filter); method public int flush(); method public void setFileDescriptor(@NonNull android.os.ParcelFileDescriptor); + method public int setRecordBufferStatusCheckIntervalHint(long); method public int start(); method public int stop(); method public long write(long); diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index a03286d3ec6f..fb1fcf8e2a06 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -173,6 +173,7 @@ public class Resources { * mThemeRefNextFlushSize is reached. */ private static final int MIN_THEME_REFS_FLUSH_SIZE = 32; + private static final int MAX_THEME_REFS_FLUSH_SIZE = 512; private int mThemeRefsNextFlushSize = MIN_THEME_REFS_FLUSH_SIZE; private int mBaseApkAssetsSize; @@ -364,10 +365,10 @@ public class Resources { // Rebase the ThemeImpls using the new ResourcesImpl. synchronized (mThemeRefs) { + cleanupThemeReferences(); final int count = mThemeRefs.size(); for (int i = 0; i < count; i++) { - WeakReference<Theme> weakThemeRef = mThemeRefs.get(i); - Theme theme = weakThemeRef != null ? weakThemeRef.get() : null; + Theme theme = mThemeRefs.get(i).get(); if (theme != null) { theme.rebase(mResourcesImpl); } @@ -2001,6 +2002,15 @@ public class Resources { private int mHashCode = 0; + private boolean containsValue(int resId, boolean force) { + for (int i = 0; i < mCount; ++i) { + if (mResId[i] == resId && mForce[i] == force) { + return true; + } + } + return false; + } + public void append(int resId, boolean force) { if (mResId == null) { mResId = new int[4]; @@ -2010,6 +2020,11 @@ public class Resources { mForce = new boolean[4]; } + // Some apps tend to keep adding same resources over and over, let's protect from it. + if (containsValue(resId, force)) { + return; + } + mResId = GrowingArrayUtils.append(mResId, mCount, resId); mForce = GrowingArrayUtils.append(mForce, mCount, force); mCount++; @@ -2073,6 +2088,19 @@ public class Resources { } } + static int nextPowerOf2(int number) { + return number < 2 ? 2 : 1 >> ((int) (Math.log(number - 1) / Math.log(2)) + 1); + } + + private void cleanupThemeReferences() { + // Clean up references to garbage collected themes + if (mThemeRefs.size() > mThemeRefsNextFlushSize) { + mThemeRefs.removeIf(ref -> ref.refersTo(null)); + mThemeRefsNextFlushSize = Math.min(Math.max(MIN_THEME_REFS_FLUSH_SIZE, + nextPowerOf2(mThemeRefs.size())), MAX_THEME_REFS_FLUSH_SIZE); + } + } + /** * Generate a new Theme object for this set of Resources. It initially * starts out empty. @@ -2083,14 +2111,8 @@ public class Resources { Theme theme = new Theme(); theme.setImpl(mResourcesImpl.newThemeImpl()); synchronized (mThemeRefs) { + cleanupThemeReferences(); mThemeRefs.add(new WeakReference<>(theme)); - - // Clean up references to garbage collected themes - if (mThemeRefs.size() > mThemeRefsNextFlushSize) { - mThemeRefs.removeIf(ref -> ref.refersTo(null)); - mThemeRefsNextFlushSize = Math.max(MIN_THEME_REFS_FLUSH_SIZE, - 2 * mThemeRefs.size()); - } } return theme; } diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index 194e1b553322..979c5a885c5e 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -53,6 +53,7 @@ import com.android.internal.telephony.SmsApplication; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -4358,6 +4359,12 @@ public final class Telephony { */ public static final String COLUMN_NAME_SOURCE = "name_source"; + /** + * The name source is unknown. + * @hide + */ + public static final int NAME_SOURCE_UNKNOWN = -1; + /** The name_source is from the carrier id. {@hide} */ public static final int NAME_SOURCE_CARRIER_ID = 0; @@ -4839,5 +4846,86 @@ public final class Telephony { * @hide */ public static final String COLUMN_USER_HANDLE = "user_handle"; + + /** All columns in {@link SimInfo} table. */ + private static final List<String> ALL_COLUMNS = List.of( + COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID, + COLUMN_ICC_ID, + COLUMN_SIM_SLOT_INDEX, + COLUMN_DISPLAY_NAME, + COLUMN_CARRIER_NAME, + COLUMN_NAME_SOURCE, + COLUMN_COLOR, + COLUMN_NUMBER, + COLUMN_DISPLAY_NUMBER_FORMAT, + COLUMN_DATA_ROAMING, + COLUMN_MCC, + COLUMN_MNC, + COLUMN_MCC_STRING, + COLUMN_MNC_STRING, + COLUMN_EHPLMNS, + COLUMN_HPLMNS, + COLUMN_SIM_PROVISIONING_STATUS, + COLUMN_IS_EMBEDDED, + COLUMN_CARD_ID, + COLUMN_ACCESS_RULES, + COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS, + COLUMN_IS_REMOVABLE, + COLUMN_CB_EXTREME_THREAT_ALERT, + COLUMN_CB_SEVERE_THREAT_ALERT, + COLUMN_CB_AMBER_ALERT, + COLUMN_CB_EMERGENCY_ALERT, + COLUMN_CB_ALERT_SOUND_DURATION, + COLUMN_CB_ALERT_REMINDER_INTERVAL, + COLUMN_CB_ALERT_VIBRATE, + COLUMN_CB_ALERT_SPEECH, + COLUMN_CB_ETWS_TEST_ALERT, + COLUMN_CB_CHANNEL_50_ALERT, + COLUMN_CB_CMAS_TEST_ALERT, + COLUMN_CB_OPT_OUT_DIALOG, + COLUMN_ENHANCED_4G_MODE_ENABLED, + COLUMN_VT_IMS_ENABLED, + COLUMN_WFC_IMS_ENABLED, + COLUMN_WFC_IMS_MODE, + COLUMN_WFC_IMS_ROAMING_MODE, + COLUMN_WFC_IMS_ROAMING_ENABLED, + COLUMN_IS_OPPORTUNISTIC, + COLUMN_GROUP_UUID, + COLUMN_IS_METERED, + COLUMN_ISO_COUNTRY_CODE, + COLUMN_CARRIER_ID, + COLUMN_PROFILE_CLASS, + COLUMN_SUBSCRIPTION_TYPE, + COLUMN_GROUP_OWNER, + COLUMN_DATA_ENABLED_OVERRIDE_RULES, + COLUMN_ENABLED_MOBILE_DATA_POLICIES, + COLUMN_IMSI, + COLUMN_UICC_APPLICATIONS_ENABLED, + COLUMN_ALLOWED_NETWORK_TYPES, + COLUMN_IMS_RCS_UCE_ENABLED, + COLUMN_CROSS_SIM_CALLING_ENABLED, + COLUMN_RCS_CONFIG, + COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS, + COLUMN_D2D_STATUS_SHARING, + COLUMN_VOIMS_OPT_IN_STATUS, + COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, + COLUMN_NR_ADVANCED_CALLING_ENABLED, + COLUMN_PHONE_NUMBER_SOURCE_CARRIER, + COLUMN_PHONE_NUMBER_SOURCE_IMS, + COLUMN_PORT_INDEX, + COLUMN_USAGE_SETTING, + COLUMN_TP_MESSAGE_REF, + COLUMN_USER_HANDLE + ); + + /** + * @return All columns in {@link SimInfo} table. + * + * @hide + */ + @NonNull + public static List<String> getAllColumns() { + return ALL_COLUMNS; + } } } diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index 13913268cad0..3b7698e3954b 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -31,9 +31,9 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; +import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; @@ -68,6 +68,8 @@ import android.view.accessibility.AccessibilityEvent; import com.android.internal.R; import com.android.internal.util.DumpUtils; +import com.android.internal.util.ObservableServiceConnection; +import com.android.internal.util.PersistentServiceConnection; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -75,7 +77,8 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; -import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.concurrent.Executor; import java.util.function.Consumer; /** @@ -225,6 +228,7 @@ public class DreamService extends Service implements Window.Callback { /** * The default value for whether to show complications on the overlay. + * * @hide */ public static final boolean DEFAULT_SHOW_COMPLICATIONS = false; @@ -251,77 +255,66 @@ public class DreamService extends Service implements Window.Callback { private DreamServiceWrapper mDreamServiceWrapper; private Runnable mDispatchAfterOnAttachedToWindow; - private final OverlayConnection mOverlayConnection; + private OverlayConnection mOverlayConnection; - private static class OverlayConnection implements ServiceConnection { + private static class OverlayConnection extends PersistentServiceConnection<IDreamOverlay> { // Overlay set during onBind. private IDreamOverlay mOverlay; - // A Queue of pending requests to execute on the overlay. - private final ArrayDeque<Consumer<IDreamOverlay>> mRequests; - - private boolean mBound; - - OverlayConnection() { - mRequests = new ArrayDeque<>(); - } - - public void bind(Context context, @Nullable ComponentName overlayService, - ComponentName dreamService) { - if (overlayService == null) { - return; + // A list of pending requests to execute on the overlay. + private final ArrayList<Consumer<IDreamOverlay>> mConsumers = new ArrayList<>(); + + private final Callback<IDreamOverlay> mCallback = new Callback<IDreamOverlay>() { + @Override + public void onConnected(ObservableServiceConnection<IDreamOverlay> connection, + IDreamOverlay service) { + mOverlay = service; + for (Consumer<IDreamOverlay> consumer : mConsumers) { + consumer.accept(mOverlay); + } } - final ServiceInfo serviceInfo = fetchServiceInfo(context, dreamService); - - final Intent overlayIntent = new Intent(); - overlayIntent.setComponent(overlayService); - overlayIntent.putExtra(EXTRA_SHOW_COMPLICATIONS, - fetchShouldShowComplications(context, serviceInfo)); - overlayIntent.putExtra(EXTRA_DREAM_COMPONENT, dreamService); - - context.bindService(overlayIntent, - this, Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE); - mBound = true; - } - - public void unbind(Context context) { - if (!mBound) { - return; + @Override + public void onDisconnected(ObservableServiceConnection<IDreamOverlay> connection, + int reason) { + mOverlay = null; } + }; - context.unbindService(this); - mBound = false; + OverlayConnection(Context context, + Executor executor, + Handler handler, + ServiceTransformer<IDreamOverlay> transformer, + Intent serviceIntent, + int flags, + int minConnectionDurationMs, + int maxReconnectAttempts, + int baseReconnectDelayMs) { + super(context, executor, handler, transformer, serviceIntent, flags, + minConnectionDurationMs, + maxReconnectAttempts, baseReconnectDelayMs); } - public void request(Consumer<IDreamOverlay> request) { - mRequests.push(request); - evaluate(); + @Override + public boolean bind() { + addCallback(mCallback); + return super.bind(); } - private void evaluate() { - if (mOverlay == null) { - return; - } - - // Any new requests that arrive during this loop will be processed synchronously after - // the loop exits. - while (!mRequests.isEmpty()) { - final Consumer<IDreamOverlay> request = mRequests.pop(); - request.accept(mOverlay); - } + @Override + public void unbind() { + removeCallback(mCallback); + super.unbind(); } - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - // Store Overlay and execute pending requests. - mOverlay = IDreamOverlay.Stub.asInterface(service); - evaluate(); + public void addConsumer(Consumer<IDreamOverlay> consumer) { + mConsumers.add(consumer); + if (mOverlay != null) { + consumer.accept(mOverlay); + } } - @Override - public void onServiceDisconnected(ComponentName name) { - // Clear Overlay binder to prevent further request processing. - mOverlay = null; + public void removeConsumer(Consumer<IDreamOverlay> consumer) { + mConsumers.remove(consumer); } } @@ -336,7 +329,6 @@ public class DreamService extends Service implements Window.Callback { public DreamService() { mDreamManager = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE)); - mOverlayConnection = new OverlayConnection(); } /** @@ -532,7 +524,7 @@ public class DreamService extends Service implements Window.Callback { return mWindow; } - /** + /** * Inflates a layout resource and set it to be the content view for this Dream. * Behaves similarly to {@link android.app.Activity#setContentView(int)}. * @@ -996,13 +988,33 @@ public class DreamService extends Service implements Window.Callback { public final IBinder onBind(Intent intent) { if (mDebug) Slog.v(mTag, "onBind() intent = " + intent); mDreamServiceWrapper = new DreamServiceWrapper(); + final ComponentName overlayComponent = intent.getParcelableExtra( + EXTRA_DREAM_OVERLAY_COMPONENT, ComponentName.class); // Connect to the overlay service if present. - if (!mWindowless) { - mOverlayConnection.bind( + if (!mWindowless && overlayComponent != null) { + final Resources resources = getResources(); + final ComponentName dreamService = new ComponentName(this, getClass()); + + final ServiceInfo serviceInfo = fetchServiceInfo(this, dreamService); + final Intent overlayIntent = new Intent() + .setComponent(overlayComponent) + .putExtra(EXTRA_SHOW_COMPLICATIONS, + fetchShouldShowComplications(this, serviceInfo)) + .putExtra(EXTRA_DREAM_COMPONENT, dreamService); + + mOverlayConnection = new OverlayConnection( /* context= */ this, - intent.getParcelableExtra(EXTRA_DREAM_OVERLAY_COMPONENT, android.content.ComponentName.class), - new ComponentName(this, getClass())); + getMainExecutor(), + mHandler, + IDreamOverlay.Stub::asInterface, + overlayIntent, + /* flags= */ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, + resources.getInteger(R.integer.config_minDreamOverlayDurationMs), + resources.getInteger(R.integer.config_dreamOverlayMaxReconnectAttempts), + resources.getInteger(R.integer.config_dreamOverlayReconnectTimeoutMs)); + + mOverlayConnection.bind(); } return mDreamServiceWrapper; @@ -1011,7 +1023,9 @@ public class DreamService extends Service implements Window.Callback { @Override public boolean onUnbind(Intent intent) { // We must unbind from any overlay connection if we are unbound before finishing. - mOverlayConnection.unbind(this); + if (mOverlayConnection != null) { + mOverlayConnection.unbind(); + } return super.onUnbind(intent); } @@ -1040,7 +1054,9 @@ public class DreamService extends Service implements Window.Callback { } mFinished = true; - mOverlayConnection.unbind(this); + if (mOverlayConnection != null) { + mOverlayConnection.unbind(); + } if (mDreamToken == null) { Slog.w(mTag, "Finish was called before the dream was attached."); @@ -1337,19 +1353,24 @@ public class DreamService extends Service implements Window.Callback { mWindow.getDecorView().addOnAttachStateChangeListener( new View.OnAttachStateChangeListener() { + private Consumer<IDreamOverlay> mDreamStartOverlayConsumer; + @Override public void onViewAttachedToWindow(View v) { mDispatchAfterOnAttachedToWindow.run(); - // Request the DreamOverlay be told to dream with dream's window parameters - // once the window has been attached. - mOverlayConnection.request(overlay -> { - try { - overlay.startDream(mWindow.getAttributes(), mOverlayCallback); - } catch (RemoteException e) { - Log.e(mTag, "could not send window attributes:" + e); - } - }); + if (mOverlayConnection != null) { + // Request the DreamOverlay be told to dream with dream's window + // parameters once the window has been attached. + mDreamStartOverlayConsumer = overlay -> { + try { + overlay.startDream(mWindow.getAttributes(), mOverlayCallback); + } catch (RemoteException e) { + Log.e(mTag, "could not send window attributes:" + e); + } + }; + mOverlayConnection.addConsumer(mDreamStartOverlayConsumer); + } } @Override @@ -1362,6 +1383,9 @@ public class DreamService extends Service implements Window.Callback { mActivity = null; finish(); } + if (mOverlayConnection != null && mDreamStartOverlayConsumer != null) { + mOverlayConnection.removeConsumer(mDreamStartOverlayConsumer); + } } }); } diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index cb8f0af10c47..d1f05ec0c05e 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -96,13 +96,6 @@ public class FeatureFlagUtils { /** @hide */ public static final String SETTINGS_AUTO_TEXT_WRAPPING = "settings_auto_text_wrapping"; - /** Flag to enable / disable the Simple Cursor accessibility feature in - * Settings. - * @hide - */ - public static final String SETTINGS_ACCESSIBILITY_SIMPLE_CURSOR = - "settings_accessibility_simple_cursor"; - /** * Enable new language and keyboard settings UI * @hide @@ -149,7 +142,6 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME, "true"); DEFAULT_FLAGS.put(SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE, "true"); DEFAULT_FLAGS.put(SETTINGS_AUTO_TEXT_WRAPPING, "false"); - DEFAULT_FLAGS.put(SETTINGS_ACCESSIBILITY_SIMPLE_CURSOR, "false"); DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_UI, "false"); DEFAULT_FLAGS.put(SETTINGS_ENABLE_SPA, "false"); DEFAULT_FLAGS.put(SETTINGS_ADB_METRICS_WRITER, "false"); diff --git a/core/java/android/view/InsetsFrameProvider.java b/core/java/android/view/InsetsFrameProvider.java index eb8687c47bed..72757807169e 100644 --- a/core/java/android/view/InsetsFrameProvider.java +++ b/core/java/android/view/InsetsFrameProvider.java @@ -59,6 +59,7 @@ public class InsetsFrameProvider implements Parcelable { private static final int HAS_INSETS_SIZE_OVERRIDE = 2; private static Rect sTmpRect = new Rect(); + private static Rect sTmpRect2 = new Rect(); /** * The type of insets to provide. @@ -88,6 +89,18 @@ public class InsetsFrameProvider implements Parcelable { */ public InsetsSizeOverride[] insetsSizeOverrides = null; + /** + * This field, if set, is indicating the insets needs to be at least the given size inside the + * display cutout safe area. This will be compared to the insets size calculated based on other + * attributes, and will be applied when this is larger. This is independent of the + * PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT in LayoutParams, as this is not going to change + * the layout of the window, but only change the insets frame. This can be applied to insets + * calculated based on all three source frames. + * + * Be cautious, this will not be in effect for the window types whose insets size is overridden. + */ + public Insets minimalInsetsSizeInDisplayCutoutSafe = null; + public InsetsFrameProvider(int type) { this(type, SOURCE_FRAME, null, null); } @@ -202,7 +215,8 @@ public class InsetsFrameProvider implements Parcelable { public static void calculateInsetsFrame(Rect displayFrame, Rect containerBounds, Rect displayCutoutSafe, Rect inOutFrame, int source, Insets insetsSize, - @WindowManager.LayoutParams.PrivateFlags int privateFlags) { + @WindowManager.LayoutParams.PrivateFlags int privateFlags, + Insets displayCutoutSafeInsetsSize) { boolean extendByCutout = false; if (source == InsetsFrameProvider.SOURCE_DISPLAY) { inOutFrame.set(displayFrame); @@ -214,6 +228,33 @@ public class InsetsFrameProvider implements Parcelable { if (insetsSize == null) { return; } + if (displayCutoutSafeInsetsSize != null) { + sTmpRect2.set(inOutFrame); + } + calculateInsetsFrame(inOutFrame, insetsSize); + + if (extendByCutout) { + WindowLayout.extendFrameByCutout(displayCutoutSafe, displayFrame, inOutFrame, sTmpRect); + } + + if (displayCutoutSafeInsetsSize != null) { + // The insets is at least with the given size within the display cutout safe area. + // Calculate the smallest size. + calculateInsetsFrame(sTmpRect2, displayCutoutSafeInsetsSize); + WindowLayout.extendFrameByCutout(displayCutoutSafe, displayFrame, sTmpRect2, sTmpRect); + // If it's larger than previous calculation, use it. + if (sTmpRect2.contains(inOutFrame)) { + inOutFrame.set(sTmpRect2); + } + } + } + + /** + * Calculate the insets frame given the insets size and the source frame. + * @param inOutFrame the source frame. + * @param insetsSize the insets size. Only the first non-zero value will be taken. + */ + private static void calculateInsetsFrame(Rect inOutFrame, Insets insetsSize) { // Only one side of the provider shall be applied. Check in the order of left - top - // right - bottom, only the first non-zero value will be applied. if (insetsSize.left != 0) { @@ -227,10 +268,6 @@ public class InsetsFrameProvider implements Parcelable { } else { inOutFrame.setEmpty(); } - - if (extendByCutout) { - WindowLayout.extendFrameByCutout(displayCutoutSafe, displayFrame, inOutFrame, sTmpRect); - } } /** diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index bc665cf09652..5c899e489347 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -12538,6 +12538,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (!enabled) { cancelPendingInputEvents(); } + notifyViewAccessibilityStateChangedIfNeeded( + AccessibilityEvent.CONTENT_CHANGE_TYPE_ENABLED); } /** diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index f86f51fc0022..b0cf504ec568 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -709,6 +709,18 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par */ public static final int CONTENT_CHANGE_TYPE_ERROR = 0x0000800; + /** + * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event: + * The source node changed its ability to interact returned by + * {@link AccessibilityNodeInfo#isEnabled}. + * The view changing content's ability to interact should call + * {@link AccessibilityNodeInfo#setEnabled} and then send this event. + * + * @see AccessibilityNodeInfo#isEnabled + * @see AccessibilityNodeInfo#setEnabled + */ + public static final int CONTENT_CHANGE_TYPE_ENABLED = 1 << 12; + /** Change type for {@link #TYPE_SPEECH_STATE_CHANGE} event: another service is speaking. */ public static final int SPEECH_STATE_SPEAKING_START = 0x00000001; @@ -836,6 +848,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par CONTENT_CHANGE_TYPE_DRAG_CANCELLED, CONTENT_CHANGE_TYPE_CONTENT_INVALID, CONTENT_CHANGE_TYPE_ERROR, + CONTENT_CHANGE_TYPE_ENABLED, }) public @interface ContentChangeTypes {} @@ -1105,6 +1118,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par case CONTENT_CHANGE_TYPE_CONTENT_INVALID: return "CONTENT_CHANGE_TYPE_CONTENT_INVALID"; case CONTENT_CHANGE_TYPE_ERROR: return "CONTENT_CHANGE_TYPE_ERROR"; + case CONTENT_CHANGE_TYPE_ENABLED: return "CONTENT_CHANGE_TYPE_ENABLED"; default: return Integer.toHexString(type); } } diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 307c55cfc2e7..d0405f0e5991 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -267,6 +267,12 @@ import java.util.function.Consumer; * they can switch to it, to confirm with the system that they know about it * and want to make it available for use.</p> * </ul> + * + * <p>If your app targets Android 11 (API level 30) or higher, the methods in + * this class each return a filtered result by the rules of + * <a href="/training/basics/intents/package-visibility">package visibility</a>, + * except for the currently connected IME. Apps having a query for the + * {@link InputMethod#SERVICE_INTERFACE} see all IMEs.</p> */ @SystemService(Context.INPUT_METHOD_SERVICE) @RequiresFeature(PackageManager.FEATURE_INPUT_METHODS) diff --git a/core/java/com/android/internal/util/ObservableServiceConnection.java b/core/java/com/android/internal/util/ObservableServiceConnection.java new file mode 100644 index 000000000000..3165d293bd91 --- /dev/null +++ b/core/java/com/android/internal/util/ObservableServiceConnection.java @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util; + +import android.annotation.CallbackExecutor; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.CallbackRegistry.NotifierCallback; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.Executor; + +/** + * {@link ObservableServiceConnection} is a concrete implementation of {@link ServiceConnection} + * that enables monitoring the status of a binder connection. It also aides in automatically + * converting a proxy into an internal wrapper type. + * + * @param <T> The type of the wrapper over the resulting service. + */ +public class ObservableServiceConnection<T> implements ServiceConnection { + /** + * An interface for converting the service proxy into a given internal wrapper type. + * + * @param <T> The type of the wrapper over the resulting service. + */ + public interface ServiceTransformer<T> { + /** + * Called to convert the service proxy to the wrapper type. + * + * @param service The service proxy to create the wrapper type from. + * @return The wrapper type. + */ + T convert(IBinder service); + } + + /** + * An interface for listening to the connection status. + * + * @param <T> The wrapper type. + */ + public interface Callback<T> { + /** + * Invoked when the service has been successfully connected to. + * + * @param connection The {@link ObservableServiceConnection} instance that is now connected + * @param service The service proxy converted into the typed wrapper. + */ + void onConnected(ObservableServiceConnection<T> connection, T service); + + /** + * Invoked when the service has been disconnected. + * + * @param connection The {@link ObservableServiceConnection} that is now disconnected. + * @param reason The reason for the disconnection. + */ + void onDisconnected(ObservableServiceConnection<T> connection, + @DisconnectReason int reason); + } + + /** + * Default state, service has not yet disconnected. + */ + public static final int DISCONNECT_REASON_NONE = 0; + /** + * Disconnection was due to the resulting binding being {@code null}. + */ + public static final int DISCONNECT_REASON_NULL_BINDING = 1; + /** + * Disconnection was due to the remote end disconnecting. + */ + public static final int DISCONNECT_REASON_DISCONNECTED = 2; + /** + * Disconnection due to the binder dying. + */ + public static final int DISCONNECT_REASON_BINDING_DIED = 3; + /** + * Disconnection from an explicit unbinding. + */ + public static final int DISCONNECT_REASON_UNBIND = 4; + + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + DISCONNECT_REASON_NONE, + DISCONNECT_REASON_NULL_BINDING, + DISCONNECT_REASON_DISCONNECTED, + DISCONNECT_REASON_BINDING_DIED, + DISCONNECT_REASON_UNBIND + }) + public @interface DisconnectReason { + } + + private final Object mLock = new Object(); + private final Context mContext; + private final Executor mExecutor; + private final ServiceTransformer<T> mTransformer; + private final Intent mServiceIntent; + private final int mFlags; + + @GuardedBy("mLock") + private T mService; + @GuardedBy("mLock") + private boolean mBoundCalled = false; + @GuardedBy("mLock") + private int mLastDisconnectReason = DISCONNECT_REASON_NONE; + + private final CallbackRegistry<Callback<T>, ObservableServiceConnection<T>, T> + mCallbackRegistry = new CallbackRegistry<>( + new NotifierCallback<Callback<T>, ObservableServiceConnection<T>, T>() { + @Override + public void onNotifyCallback(Callback<T> callback, + ObservableServiceConnection<T> sender, + int disconnectReason, T service) { + mExecutor.execute(() -> { + synchronized (mLock) { + if (service != null) { + callback.onConnected(sender, service); + } else if (mLastDisconnectReason != DISCONNECT_REASON_NONE) { + callback.onDisconnected(sender, disconnectReason); + } + } + }); + } + }); + + /** + * Default constructor for {@link ObservableServiceConnection}. + * + * @param context The context from which the service will be bound with. + * @param executor The executor for connection callbacks to be delivered on + * @param transformer A {@link ObservableServiceConnection.ServiceTransformer} for transforming + * the resulting service into a desired type. + */ + public ObservableServiceConnection(@NonNull Context context, + @NonNull @CallbackExecutor Executor executor, + @NonNull ServiceTransformer<T> transformer, + Intent serviceIntent, + int flags) { + mContext = context; + mExecutor = executor; + mTransformer = transformer; + mServiceIntent = serviceIntent; + mFlags = flags; + } + + /** + * Initiate binding to the service. + * + * @return {@code true} if initiating binding succeed, {@code false} if the binding failed or + * if this service is already bound. Regardless of the return value, you should later call + * {@link #unbind()} to release the connection. + */ + public boolean bind() { + synchronized (mLock) { + if (mBoundCalled) { + return false; + } + final boolean bindResult = + mContext.bindService(mServiceIntent, mFlags, mExecutor, this); + mBoundCalled = true; + return bindResult; + } + } + + /** + * Disconnect from the service if bound. + */ + public void unbind() { + onDisconnected(DISCONNECT_REASON_UNBIND); + } + + /** + * Adds a callback for receiving connection updates. + * + * @param callback The {@link Callback} to receive future updates. + */ + public void addCallback(Callback<T> callback) { + mCallbackRegistry.add(callback); + mExecutor.execute(() -> { + synchronized (mLock) { + if (mService != null) { + callback.onConnected(this, mService); + } else if (mLastDisconnectReason != DISCONNECT_REASON_NONE) { + callback.onDisconnected(this, mLastDisconnectReason); + } + } + }); + } + + /** + * Removes previously added callback from receiving future connection updates. + * + * @param callback The {@link Callback} to be removed. + */ + public void removeCallback(Callback<T> callback) { + synchronized (mLock) { + mCallbackRegistry.remove(callback); + } + } + + private void onDisconnected(@DisconnectReason int reason) { + synchronized (mLock) { + if (!mBoundCalled) { + return; + } + mBoundCalled = false; + mLastDisconnectReason = reason; + mContext.unbindService(this); + mService = null; + mCallbackRegistry.notifyCallbacks(this, reason, null); + } + } + + @Override + public final void onServiceConnected(ComponentName name, IBinder service) { + synchronized (mLock) { + mService = mTransformer.convert(service); + mLastDisconnectReason = DISCONNECT_REASON_NONE; + mCallbackRegistry.notifyCallbacks(this, mLastDisconnectReason, mService); + } + } + + @Override + public final void onServiceDisconnected(ComponentName name) { + onDisconnected(DISCONNECT_REASON_DISCONNECTED); + } + + @Override + public final void onBindingDied(ComponentName name) { + onDisconnected(DISCONNECT_REASON_BINDING_DIED); + } + + @Override + public final void onNullBinding(ComponentName name) { + onDisconnected(DISCONNECT_REASON_NULL_BINDING); + } +} diff --git a/core/java/com/android/internal/util/PersistentServiceConnection.java b/core/java/com/android/internal/util/PersistentServiceConnection.java new file mode 100644 index 000000000000..d2017347bd64 --- /dev/null +++ b/core/java/com/android/internal/util/PersistentServiceConnection.java @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util; + +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Handler; +import android.os.SystemClock; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; + +import java.util.concurrent.Executor; + +/** + * {@link PersistentServiceConnection} is a concrete implementation of {@link ServiceConnection} + * that maintains the binder connection by handling reconnection when a failure occurs. + * + * @param <T> The transformed connection type handled by the service. + * + * When the target process is killed (by OOM-killer, force-stopped, crash, etc..) then this class + * will trigger a reconnection to the target. This should be used carefully. + * + * NOTE: This class does *not* handle package-updates -- i.e. even if the binding dies due to + * the target package being updated, this class won't reconnect. This is because this class doesn't + * know what to do when the service component has gone missing, for example. If the user of this + * class wants to restore the connection, then it should call {@link #unbind()} and {@link #bind} + * explicitly. + */ +public class PersistentServiceConnection<T> extends ObservableServiceConnection<T> { + private final Callback<T> mConnectionCallback = new Callback<T>() { + private long mConnectedTime; + + @Override + public void onConnected(ObservableServiceConnection<T> connection, T service) { + mConnectedTime = mInjector.uptimeMillis(); + } + + @Override + public void onDisconnected(ObservableServiceConnection<T> connection, + @DisconnectReason int reason) { + if (reason == DISCONNECT_REASON_UNBIND) return; + synchronized (mLock) { + if ((mInjector.uptimeMillis() - mConnectedTime) > mMinConnectionDurationMs) { + mReconnectAttempts = 0; + bindInternalLocked(); + } else { + scheduleConnectionAttemptLocked(); + } + } + } + }; + + private final Object mLock = new Object(); + private final Injector mInjector; + private final Handler mHandler; + private final int mMinConnectionDurationMs; + private final int mMaxReconnectAttempts; + private final int mBaseReconnectDelayMs; + @GuardedBy("mLock") + private int mReconnectAttempts; + @GuardedBy("mLock") + private Object mCancelToken; + + private final Runnable mConnectRunnable = new Runnable() { + @Override + public void run() { + synchronized (mLock) { + mCancelToken = null; + bindInternalLocked(); + } + } + }; + + /** + * Default constructor for {@link PersistentServiceConnection}. + * + * @param context The context from which the service will be bound with. + * @param executor The executor for connection callbacks to be delivered on + * @param transformer A {@link ServiceTransformer} for transforming + */ + public PersistentServiceConnection(Context context, + Executor executor, + Handler handler, + ServiceTransformer<T> transformer, + Intent serviceIntent, + int flags, + int minConnectionDurationMs, + int maxReconnectAttempts, + int baseReconnectDelayMs) { + this(context, + executor, + handler, + transformer, + serviceIntent, + flags, + minConnectionDurationMs, + maxReconnectAttempts, + baseReconnectDelayMs, + new Injector()); + } + + @VisibleForTesting + public PersistentServiceConnection( + Context context, + Executor executor, + Handler handler, + ServiceTransformer<T> transformer, + Intent serviceIntent, + int flags, + int minConnectionDurationMs, + int maxReconnectAttempts, + int baseReconnectDelayMs, + Injector injector) { + super(context, executor, transformer, serviceIntent, flags); + mHandler = handler; + mMinConnectionDurationMs = minConnectionDurationMs; + mMaxReconnectAttempts = maxReconnectAttempts; + mBaseReconnectDelayMs = baseReconnectDelayMs; + mInjector = injector; + } + + /** {@inheritDoc} */ + @Override + public boolean bind() { + synchronized (mLock) { + addCallback(mConnectionCallback); + mReconnectAttempts = 0; + return bindInternalLocked(); + } + } + + @GuardedBy("mLock") + private boolean bindInternalLocked() { + return super.bind(); + } + + /** {@inheritDoc} */ + @Override + public void unbind() { + synchronized (mLock) { + removeCallback(mConnectionCallback); + cancelPendingConnectionAttemptLocked(); + super.unbind(); + } + } + + @GuardedBy("mLock") + private void cancelPendingConnectionAttemptLocked() { + if (mCancelToken != null) { + mHandler.removeCallbacksAndMessages(mCancelToken); + mCancelToken = null; + } + } + + @GuardedBy("mLock") + private void scheduleConnectionAttemptLocked() { + cancelPendingConnectionAttemptLocked(); + + if (mReconnectAttempts >= mMaxReconnectAttempts) { + return; + } + + final long reconnectDelayMs = + (long) Math.scalb(mBaseReconnectDelayMs, mReconnectAttempts); + + mCancelToken = new Object(); + mHandler.postDelayed(mConnectRunnable, mCancelToken, reconnectDelayMs); + mReconnectAttempts++; + } + + /** + * Injector for testing + */ + @VisibleForTesting + public static class Injector { + /** + * Returns milliseconds since boot, not counting time spent in deep sleep. Can be overridden + * in tests with a fake clock. + */ + public long uptimeMillis() { + return SystemClock.uptimeMillis(); + } + } +} diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 47faf2a2ebf7..38344788a100 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -553,6 +553,14 @@ <!-- If this is true, then keep dreaming when undocking. --> <bool name="config_keepDreamingWhenUndocking">false</bool> + <!-- The timeout (in ms) to wait before attempting to reconnect to the dream overlay service if + it becomes disconnected --> + <integer name="config_dreamOverlayReconnectTimeoutMs">1000</integer> <!-- 1 second --> + <!-- The maximum number of times to attempt reconnecting to the dream overlay service --> + <integer name="config_dreamOverlayMaxReconnectAttempts">3</integer> + <!-- The duration after which the dream overlay connection should be considered stable --> + <integer name="config_minDreamOverlayDurationMs">10000</integer> <!-- 10 seconds --> + <!-- Auto-rotation behavior --> <!-- If true, enables auto-rotation features using the accelerometer. diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index b42db13e1ac2..2fbf8034c27e 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2238,6 +2238,9 @@ <java-symbol type="array" name="config_supportedDreamComplications" /> <java-symbol type="array" name="config_disabledDreamComponents" /> <java-symbol type="bool" name="config_dismissDreamOnActivityStart" /> + <java-symbol type="integer" name="config_dreamOverlayReconnectTimeoutMs" /> + <java-symbol type="integer" name="config_dreamOverlayMaxReconnectAttempts" /> + <java-symbol type="integer" name="config_minDreamOverlayDurationMs" /> <java-symbol type="string" name="config_loggable_dream_prefix" /> <java-symbol type="string" name="config_dozeComponent" /> <java-symbol type="string" name="enable_explore_by_touch_warning_title" /> diff --git a/core/tests/utiltests/Android.bp b/core/tests/utiltests/Android.bp index adc3676f7b93..3798da592cd5 100644 --- a/core/tests/utiltests/Android.bp +++ b/core/tests/utiltests/Android.bp @@ -34,6 +34,7 @@ android_test { "mockito-target-minus-junit4", "androidx.test.ext.junit", "truth-prebuilt", + "servicestests-utils", ], libs: [ diff --git a/core/tests/utiltests/src/com/android/internal/util/ObservableServiceConnectionTest.java b/core/tests/utiltests/src/com/android/internal/util/ObservableServiceConnectionTest.java new file mode 100644 index 000000000000..d124ad9ddfb0 --- /dev/null +++ b/core/tests/utiltests/src/com/android/internal/util/ObservableServiceConnectionTest.java @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.os.IBinder; + +import androidx.test.filters.SmallTest; + +import com.android.internal.util.ObservableServiceConnection.ServiceTransformer; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayDeque; +import java.util.Objects; +import java.util.Queue; +import java.util.concurrent.Executor; + +@SmallTest +public class ObservableServiceConnectionTest { + private static final ComponentName COMPONENT_NAME = + new ComponentName("test.package", "component"); + + public static class Foo { + int mValue; + + Foo(int value) { + mValue = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Foo)) return false; + Foo foo = (Foo) o; + return mValue == foo.mValue; + } + + @Override + public int hashCode() { + return Objects.hash(mValue); + } + } + + + @Mock + private Context mContext; + @Mock + private Intent mIntent; + @Mock + private Foo mResult; + @Mock + private IBinder mBinder; + @Mock + private ServiceTransformer<Foo> mTransformer; + @Mock + private ObservableServiceConnection.Callback<Foo> mCallback; + private final FakeExecutor mExecutor = new FakeExecutor(); + private ObservableServiceConnection<Foo> mConnection; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mConnection = new ObservableServiceConnection<>( + mContext, + mExecutor, + mTransformer, + mIntent, + /* flags= */ Context.BIND_AUTO_CREATE); + } + + @After + public void tearDown() { + mExecutor.clearAll(); + } + + @Test + public void testConnect() { + // Register twice to ensure only one callback occurs. + mConnection.addCallback(mCallback); + mConnection.addCallback(mCallback); + + mExecutor.runAll(); + mConnection.bind(); + + // Ensure that no callbacks happen before connection. + verify(mCallback, never()).onConnected(any(), any()); + verify(mCallback, never()).onDisconnected(any(), anyInt()); + + when(mTransformer.convert(mBinder)).thenReturn(mResult); + mConnection.onServiceConnected(COMPONENT_NAME, mBinder); + + mExecutor.runAll(); + verify(mCallback, times(1)).onConnected(mConnection, mResult); + } + + @Test + public void testDisconnectBeforeBind() { + mConnection.addCallback(mCallback); + mExecutor.runAll(); + mConnection.onServiceDisconnected(COMPONENT_NAME); + mExecutor.runAll(); + // Disconnects before binds should be ignored. + verify(mCallback, never()).onDisconnected(eq(mConnection), anyInt()); + } + + @Test + public void testDisconnect() { + mConnection.addCallback(mCallback); + mExecutor.runAll(); + mConnection.bind(); + mConnection.onServiceDisconnected(COMPONENT_NAME); + + // Ensure the callback doesn't get triggered until the executor runs. + verify(mCallback, never()).onDisconnected(eq(mConnection), anyInt()); + mExecutor.runAll(); + // Ensure proper disconnect reason reported. + verify(mCallback, times(1)).onDisconnected(mConnection, + ObservableServiceConnection.DISCONNECT_REASON_DISCONNECTED); + // Verify unbound from service. + verify(mContext, times(1)).unbindService(mConnection); + + clearInvocations(mContext); + // Ensure unbind after disconnect has no effect on the connection + mConnection.unbind(); + verify(mContext, never()).unbindService(mConnection); + } + + @Test + public void testBindingDied() { + mConnection.addCallback(mCallback); + mExecutor.runAll(); + mConnection.bind(); + mConnection.onBindingDied(COMPONENT_NAME); + + // Ensure the callback doesn't get triggered until the executor runs. + verify(mCallback, never()).onDisconnected(eq(mConnection), anyInt()); + mExecutor.runAll(); + // Ensure proper disconnect reason reported. + verify(mCallback, times(1)).onDisconnected(mConnection, + ObservableServiceConnection.DISCONNECT_REASON_BINDING_DIED); + // Verify unbound from service. + verify(mContext, times(1)).unbindService(mConnection); + } + + @Test + public void testNullBinding() { + mConnection.addCallback(mCallback); + mExecutor.runAll(); + mConnection.bind(); + mConnection.onNullBinding(COMPONENT_NAME); + + // Ensure the callback doesn't get triggered until the executor runs. + verify(mCallback, never()).onDisconnected(eq(mConnection), anyInt()); + mExecutor.runAll(); + // Ensure proper disconnect reason reported. + verify(mCallback, times(1)).onDisconnected(mConnection, + ObservableServiceConnection.DISCONNECT_REASON_NULL_BINDING); + // Verify unbound from service. + verify(mContext, times(1)).unbindService(mConnection); + } + + @Test + public void testUnbind() { + mConnection.addCallback(mCallback); + mExecutor.runAll(); + mConnection.bind(); + mConnection.unbind(); + + // Ensure the callback doesn't get triggered until the executor runs. + verify(mCallback, never()).onDisconnected(eq(mConnection), anyInt()); + mExecutor.runAll(); + verify(mCallback).onDisconnected(mConnection, + ObservableServiceConnection.DISCONNECT_REASON_UNBIND); + } + + static class FakeExecutor implements Executor { + private final Queue<Runnable> mQueue = new ArrayDeque<>(); + + @Override + public void execute(Runnable command) { + mQueue.add(command); + } + + public void runAll() { + while (!mQueue.isEmpty()) { + mQueue.remove().run(); + } + } + + public void clearAll() { + while (!mQueue.isEmpty()) { + mQueue.remove(); + } + } + } +} diff --git a/core/tests/utiltests/src/com/android/internal/util/PersistentServiceConnectionTest.java b/core/tests/utiltests/src/com/android/internal/util/PersistentServiceConnectionTest.java new file mode 100644 index 000000000000..fee46545ac62 --- /dev/null +++ b/core/tests/utiltests/src/com/android/internal/util/PersistentServiceConnectionTest.java @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.os.IBinder; + +import com.android.internal.util.ObservableServiceConnection.ServiceTransformer; +import com.android.server.testutils.OffsettableClock; +import com.android.server.testutils.TestHandler; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayDeque; +import java.util.Queue; +import java.util.concurrent.Executor; + +public class PersistentServiceConnectionTest { + private static final ComponentName COMPONENT_NAME = + new ComponentName("test.package", "component"); + private static final int MAX_RETRIES = 2; + private static final int RETRY_DELAY_MS = 1000; + private static final int CONNECTION_MIN_DURATION_MS = 5000; + private PersistentServiceConnection<Proxy> mConnection; + + public static class Proxy { + } + + @Mock + private Context mContext; + @Mock + private Intent mIntent; + @Mock + private Proxy mResult; + @Mock + private IBinder mBinder; + @Mock + private ServiceTransformer<Proxy> mTransformer; + @Mock + private ObservableServiceConnection.Callback<Proxy> mCallback; + private TestHandler mHandler; + private final FakeExecutor mFakeExecutor = new FakeExecutor(); + private OffsettableClock mClock; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + + mClock = new OffsettableClock.Stopped(); + mHandler = spy(new TestHandler(null, mClock)); + + mConnection = new PersistentServiceConnection<>( + mContext, + mFakeExecutor, + mHandler, + mTransformer, + mIntent, + /* flags= */ Context.BIND_AUTO_CREATE, + CONNECTION_MIN_DURATION_MS, + MAX_RETRIES, + RETRY_DELAY_MS, + new TestInjector(mClock)); + + mClock.fastForward(1000); + mConnection.addCallback(mCallback); + when(mTransformer.convert(mBinder)).thenReturn(mResult); + } + + @After + public void tearDown() { + mFakeExecutor.clearAll(); + } + + @Test + public void testConnect() { + mConnection.bind(); + mConnection.onServiceConnected(COMPONENT_NAME, mBinder); + mFakeExecutor.runAll(); + // Ensure that we did not schedule a retry + verify(mHandler, never()).postDelayed(any(), anyLong()); + } + + @Test + public void testRetryOnBindFailure() { + mConnection.bind(); + + verify(mContext, times(1)).bindService( + eq(mIntent), + anyInt(), + eq(mFakeExecutor), + eq(mConnection)); + + // After disconnect, a reconnection should be attempted after the RETRY_DELAY_MS + mConnection.onServiceDisconnected(COMPONENT_NAME); + mFakeExecutor.runAll(); + advanceTime(RETRY_DELAY_MS); + verify(mContext, times(2)).bindService( + eq(mIntent), + anyInt(), + eq(mFakeExecutor), + eq(mConnection)); + + // Reconnect attempt #2 + mConnection.onServiceDisconnected(COMPONENT_NAME); + mFakeExecutor.runAll(); + advanceTime(RETRY_DELAY_MS * 2); + verify(mContext, times(3)).bindService( + eq(mIntent), + anyInt(), + eq(mFakeExecutor), + eq(mConnection)); + + // There should be no more reconnect attempts, since the maximum is 2 + mConnection.onServiceDisconnected(COMPONENT_NAME); + mFakeExecutor.runAll(); + advanceTime(RETRY_DELAY_MS * 4); + verify(mContext, times(3)).bindService( + eq(mIntent), + anyInt(), + eq(mFakeExecutor), + eq(mConnection)); + } + + @Test + public void testManualUnbindDoesNotReconnect() { + mConnection.bind(); + + verify(mContext, times(1)).bindService( + eq(mIntent), + anyInt(), + eq(mFakeExecutor), + eq(mConnection)); + + mConnection.unbind(); + // Ensure that disconnection after unbind does not reconnect. + mConnection.onServiceDisconnected(COMPONENT_NAME); + mFakeExecutor.runAll(); + advanceTime(RETRY_DELAY_MS); + + verify(mContext, times(1)).bindService( + eq(mIntent), + anyInt(), + eq(mFakeExecutor), + eq(mConnection)); + } + + private void advanceTime(long millis) { + mClock.fastForward(millis); + mHandler.timeAdvance(); + } + + static class TestInjector extends PersistentServiceConnection.Injector { + private final OffsettableClock mClock; + + TestInjector(OffsettableClock clock) { + mClock = clock; + } + + @Override + public long uptimeMillis() { + return mClock.now(); + } + } + + static class FakeExecutor implements Executor { + private final Queue<Runnable> mQueue = new ArrayDeque<>(); + + @Override + public void execute(Runnable command) { + mQueue.add(command); + } + + public void runAll() { + while (!mQueue.isEmpty()) { + mQueue.remove().run(); + } + } + + public void clearAll() { + while (!mQueue.isEmpty()) { + mQueue.remove(); + } + } + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java index 419e62daf586..c2ad1a98d167 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java @@ -118,6 +118,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange private boolean mFreezeDividerWindow = false; private int mOrientation; private int mRotation; + private int mDensity; private final boolean mDimNonImeSide; @@ -290,9 +291,11 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange final int rotation = configuration.windowConfiguration.getRotation(); final Rect rootBounds = configuration.windowConfiguration.getBounds(); final int orientation = configuration.orientation; + final int density = configuration.densityDpi; if (mOrientation == orientation && mRotation == rotation + && mDensity == density && mRootBounds.equals(rootBounds)) { return false; } @@ -303,6 +306,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange mTempRect.set(mRootBounds); mRootBounds.set(rootBounds); mRotation = rotation; + mDensity = density; mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, null); initDividerPosition(mTempRect); updateInvisibleRect(); diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt index 3d8525b3d4ad..1dc03b9b8900 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt @@ -18,12 +18,12 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper +import com.android.server.wm.flicker.helpers.SimpleAppHelper import org.junit.Test /** Base class for pip expand tests */ abstract class ExitPipToAppTransition(testSpec: FlickerTestParameter) : PipTransition(testSpec) { - protected val testApp = FixedOrientationAppHelper(instrumentation) + protected val testApp = SimpleAppHelper(instrumentation) /** * Checks that the pip app window remains inside the display bounds throughout the whole diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java index 695550dd8fa5..f6d6c03bc2ee 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java @@ -16,6 +16,7 @@ package com.android.wm.shell.common.split; +import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static com.google.common.truth.Truth.assertThat; @@ -91,6 +92,14 @@ public class SplitLayoutTests extends ShellTestCase { // Verify updateConfiguration returns true if the root bounds changed. config.windowConfiguration.setBounds(new Rect(0, 0, 2160, 1080)); assertThat(mSplitLayout.updateConfiguration(config)).isTrue(); + + // Verify updateConfiguration returns true if the orientation changed. + config.orientation = ORIENTATION_LANDSCAPE; + assertThat(mSplitLayout.updateConfiguration(config)).isTrue(); + + // Verify updateConfiguration returns true if the density changed. + config.densityDpi = 123; + assertThat(mSplitLayout.updateConfiguration(config)).isTrue(); } @Test diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 235700b27c25..1381bdd6a50d 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -1068,7 +1068,7 @@ base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::ResolveBag( base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::GetBag(uint32_t resid) const { std::vector<uint32_t> found_resids; const auto bag = GetBag(resid, found_resids); - cached_bag_resid_stacks_.emplace(resid, found_resids); + cached_bag_resid_stacks_.emplace(resid, std::move(found_resids)); return bag; } @@ -1468,7 +1468,6 @@ base::expected<std::monostate, NullOrIOError> Theme::ApplyStyle(uint32_t resid, continue; } - Theme::Entry new_entry{attr_res_id, it->cookie, (*bag)->type_spec_flags, it->value}; auto entry_it = std::lower_bound(entries_.begin(), entries_.end(), attr_res_id, ThemeEntryKeyComparer{}); if (entry_it != entries_.end() && entry_it->attr_res_id == attr_res_id) { @@ -1477,10 +1476,10 @@ base::expected<std::monostate, NullOrIOError> Theme::ApplyStyle(uint32_t resid, /// true. entries_.erase(entry_it); } else if (force) { - *entry_it = new_entry; + *entry_it = Entry{attr_res_id, it->cookie, (*bag)->type_spec_flags, it->value}; } } else { - entries_.insert(entry_it, new_entry); + entries_.insert(entry_it, Entry{attr_res_id, it->cookie, (*bag)->type_spec_flags, it->value}); } } return {}; diff --git a/media/java/android/media/tv/tuner/TunerVersionChecker.java b/media/java/android/media/tv/tuner/TunerVersionChecker.java index 3e13bed0afbd..f29a93cbb228 100644 --- a/media/java/android/media/tv/tuner/TunerVersionChecker.java +++ b/media/java/android/media/tv/tuner/TunerVersionChecker.java @@ -59,6 +59,10 @@ public final class TunerVersionChecker { * Tuner version 2.0. */ public static final int TUNER_VERSION_2_0 = (2 << 16); + /** + * Tuner version 3.0. + */ + public static final int TUNER_VERSION_3_0 = (3 << 16); /** * Get the current running Tuner version. diff --git a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java index 11e699981e80..06802409baf7 100644 --- a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java +++ b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java @@ -23,6 +23,7 @@ import android.annotation.SystemApi; import android.media.tv.tuner.Tuner; import android.media.tv.tuner.Tuner.Result; import android.media.tv.tuner.TunerUtils; +import android.media.tv.tuner.TunerVersionChecker; import android.media.tv.tuner.filter.Filter; import android.os.ParcelFileDescriptor; import android.os.Process; @@ -91,6 +92,7 @@ public class DvrPlayback implements AutoCloseable { private native int nativeAttachFilter(Filter filter); private native int nativeDetachFilter(Filter filter); private native int nativeConfigureDvr(DvrSettings settings); + private native int nativeSetStatusCheckIntervalHint(long durationInMs); private native int nativeStartDvr(); private native int nativeStopDvr(); private native int nativeFlushDvr(); @@ -177,6 +179,35 @@ public class DvrPlayback implements AutoCloseable { } /** + * Set playback buffer status check time interval. + * + * This status check time interval will be used by the Dvr to decide how often to evaluate + * data. The default value will be decided by HAL if it’s not set. + * + * <p>This functionality is only available in Tuner version 3.0 and higher and will otherwise + * return a {@link Tuner#RESULT_UNAVAILABLE}. Use {@link TunerVersionChecker#getTunerVersion()} + * to get the version information. + * + * @param durationInMs specifies the duration of the delay in milliseconds. + * + * @return one of the following results: + * {@link Tuner#RESULT_SUCCESS} if succeed, + * {@link Tuner#RESULT_UNAVAILABLE} if Dvr is unavailable or unsupported HAL versions, + * {@link Tuner#RESULT_NOT_INITIALIZED} if Dvr is not initialized, + * {@link Tuner#RESULT_INVALID_STATE} if Dvr is in a wrong state, + * {@link Tuner#RESULT_INVALID_ARGUMENT} if the input parameter is invalid. + */ + @Result + public int setPlaybackBufferStatusCheckIntervalHint(long durationInMs) { + if (!TunerVersionChecker.checkHigherOrEqualVersionTo( + TunerVersionChecker.TUNER_VERSION_3_0, "Set status check interval hint")) { + // no-op + return Tuner.RESULT_UNAVAILABLE; + } + return nativeSetStatusCheckIntervalHint(durationInMs); + } + + /** * Starts DVR. * * <p>Starts consuming playback data or producing data for recording. diff --git a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java index e72026aab992..1a658320a1a9 100644 --- a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java +++ b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java @@ -22,6 +22,7 @@ import android.annotation.SystemApi; import android.media.tv.tuner.Tuner; import android.media.tv.tuner.Tuner.Result; import android.media.tv.tuner.TunerUtils; +import android.media.tv.tuner.TunerVersionChecker; import android.media.tv.tuner.filter.Filter; import android.os.ParcelFileDescriptor; import android.os.Process; @@ -53,6 +54,7 @@ public class DvrRecorder implements AutoCloseable { private native int nativeAttachFilter(Filter filter); private native int nativeDetachFilter(Filter filter); private native int nativeConfigureDvr(DvrSettings settings); + private native int nativeSetStatusCheckIntervalHint(long durationInMs); private native int nativeStartDvr(); private native int nativeStopDvr(); private native int nativeFlushDvr(); @@ -131,6 +133,35 @@ public class DvrRecorder implements AutoCloseable { } /** + * Set record buffer status check time interval. + * + * This status check time interval will be used by the Dvr to decide how often to evaluate + * data. The default value will be decided by HAL if it’s not set. + * + * <p>This functionality is only available in Tuner version 3.0 and higher and will otherwise + * return a {@link Tuner#RESULT_UNAVAILABLE}. Use {@link TunerVersionChecker#getTunerVersion()} + * to get the version information. + * + * @param durationInMs specifies the duration of the delay in milliseconds. + * + * @return one of the following results: + * {@link Tuner#RESULT_SUCCESS} if succeed, + * {@link Tuner#RESULT_UNAVAILABLE} if Dvr is unavailable or unsupported HAL versions, + * {@link Tuner#RESULT_NOT_INITIALIZED} if Dvr is not initialized, + * {@link Tuner#RESULT_INVALID_STATE} if Dvr is in a wrong state, + * {@link Tuner#RESULT_INVALID_ARGUMENT} if the input parameter is invalid. + */ + @Result + public int setRecordBufferStatusCheckIntervalHint(long durationInMs) { + if (!TunerVersionChecker.checkHigherOrEqualVersionTo( + TunerVersionChecker.TUNER_VERSION_3_0, "Set status check interval hint")) { + // no-op + return Tuner.RESULT_UNAVAILABLE; + } + return nativeSetStatusCheckIntervalHint(durationInMs); + } + + /** * Starts DVR. * * <p>Starts consuming playback data or producing data for recording. diff --git a/media/jni/Android.bp b/media/jni/Android.bp index 96a3781af3a8..a0304bb5c04b 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -175,7 +175,7 @@ cc_library_shared { shared_libs: [ "android.hardware.graphics.bufferqueue@2.0", - "android.hardware.tv.tuner-V1-ndk", + "android.hardware.tv.tuner-V2-ndk", "libbinder_ndk", "libandroid_runtime", "libcutils", diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index 244730b76df2..c18edcd8689b 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -4485,6 +4485,17 @@ static jint android_media_tv_Tuner_configure_dvr(JNIEnv *env, jobject dvr, jobje return (jint)result; } +static jint android_media_tv_Tuner_set_status_check_interval_hint(JNIEnv *env, jobject dvr, + jlong durationInMs) { + sp<DvrClient> dvrClient = getDvrClient(env, dvr); + if (dvrClient == nullptr) { + ALOGD("Failed to set status check interval hint: dvr client not found"); + return (int)Result::NOT_INITIALIZED; + } + Result result = dvrClient->setStatusCheckIntervalHint(durationInMs); + return (jint)result; +} + static jint android_media_tv_Tuner_start_dvr(JNIEnv *env, jobject dvr) { sp<DvrClient> dvrClient = getDvrClient(env, dvr); if (dvrClient == nullptr) { @@ -4828,6 +4839,8 @@ static const JNINativeMethod gDvrRecorderMethods[] = { (void *)android_media_tv_Tuner_detach_filter }, { "nativeConfigureDvr", "(Landroid/media/tv/tuner/dvr/DvrSettings;)I", (void *)android_media_tv_Tuner_configure_dvr }, + { "nativeSetStatusCheckIntervalHint", "(J)I", + (void *)android_media_tv_Tuner_set_status_check_interval_hint}, { "nativeStartDvr", "()I", (void *)android_media_tv_Tuner_start_dvr }, { "nativeStopDvr", "()I", (void *)android_media_tv_Tuner_stop_dvr }, { "nativeFlushDvr", "()I", (void *)android_media_tv_Tuner_flush_dvr }, @@ -4844,6 +4857,8 @@ static const JNINativeMethod gDvrPlaybackMethods[] = { (void *)android_media_tv_Tuner_detach_filter}, { "nativeConfigureDvr", "(Landroid/media/tv/tuner/dvr/DvrSettings;)I", (void *)android_media_tv_Tuner_configure_dvr}, + { "nativeSetStatusCheckIntervalHint", "(J)I", + (void *)android_media_tv_Tuner_set_status_check_interval_hint}, { "nativeStartDvr", "()I", (void *)android_media_tv_Tuner_start_dvr}, { "nativeStopDvr", "()I", (void *)android_media_tv_Tuner_stop_dvr}, { "nativeFlushDvr", "()I", (void *)android_media_tv_Tuner_flush_dvr}, diff --git a/media/jni/tuner/DvrClient.cpp b/media/jni/tuner/DvrClient.cpp index 05683b661716..6e4705251724 100644 --- a/media/jni/tuner/DvrClient.cpp +++ b/media/jni/tuner/DvrClient.cpp @@ -303,7 +303,17 @@ Result DvrClient::close() { return Result::INVALID_STATE; } +Result DvrClient::setStatusCheckIntervalHint(int64_t durationInMs) { + if (mTunerDvr == nullptr) { + return Result::INVALID_STATE; + } + if (durationInMs < 0) { + return Result::INVALID_ARGUMENT; + } + Status s = mTunerDvr->setStatusCheckIntervalHint(durationInMs); + return ClientHelper::getServiceSpecificErrorCode(s); +} /////////////// TunerDvrCallback /////////////////////// TunerDvrCallback::TunerDvrCallback(sp<DvrClientCallback> dvrClientCallback) : mDvrClientCallback(dvrClientCallback) {} diff --git a/media/jni/tuner/DvrClient.h b/media/jni/tuner/DvrClient.h index 61c0325813a4..40ed75b365c3 100644 --- a/media/jni/tuner/DvrClient.h +++ b/media/jni/tuner/DvrClient.h @@ -126,6 +126,11 @@ public: */ Result close(); + /** + * Set status check time interval. + */ + Result setStatusCheckIntervalHint(int64_t durationInMs); + private: /** * An AIDL Tuner Dvr Singleton assigned at the first time the Tuner Client diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 761aa7e9b09c..cd9f85111c2d 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -2333,7 +2333,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab */ public void requestFaceAuth(boolean userInitiatedRequest, @FaceAuthApiRequestReason String reason) { - mLogger.logFaceAuthRequested(userInitiatedRequest); + mLogger.logFaceAuthRequested(userInitiatedRequest, reason); updateFaceListeningState(BIOMETRIC_ACTION_START, apiRequestReasonToUiEvent(reason)); } diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt index 54cec7132bfa..2eee95738b7b 100644 --- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt +++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt @@ -108,10 +108,11 @@ class KeyguardUpdateMonitorLogger @Inject constructor( }, { "Face help received, msgId: $int1 msg: $str1" }) } - fun logFaceAuthRequested(userInitiatedRequest: Boolean) { - logBuffer.log(TAG, DEBUG, - { bool1 = userInitiatedRequest }, - { "requestFaceAuth() userInitiated=$bool1" }) + fun logFaceAuthRequested(userInitiatedRequest: Boolean, reason: String) { + logBuffer.log(TAG, DEBUG, { + bool1 = userInitiatedRequest + str1 = reason + }, { "requestFaceAuth() userInitiated=$bool1 reason=$str1" }) } fun logFaceAuthSuccess(userId: Int) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index 19ffa30324b8..3e796cd0c879 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -806,7 +806,7 @@ public class AuthContainerView extends LinearLayout } mContainerState = STATE_GONE; if (isAttachedToWindow()) { - mWindowManager.removeView(this); + mWindowManager.removeViewImmediate(this); } } diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java index fcf11ef350fd..8aaadeffae12 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java @@ -300,8 +300,8 @@ public class Flags { public static final UnreleasedFlag SCREENSHOT_REQUEST_PROCESSOR = new UnreleasedFlag(1300); public static final UnreleasedFlag SCREENSHOT_WORK_PROFILE_POLICY = new UnreleasedFlag(1301); - // 1400 - columbus, b/242800729 - public static final UnreleasedFlag QUICK_TAP_IN_PCC = new UnreleasedFlag(1400); + // 1400 - columbus + public static final ReleasedFlag QUICK_TAP_IN_PCC = new ReleasedFlag(1400); // 1500 - chooser public static final UnreleasedFlag CHOOSER_UNBUNDLED = new UnreleasedFlag(1500); diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java index 0c5564b34b15..28aa19e18e80 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java @@ -322,7 +322,7 @@ public class LogModule { @SysUISingleton @KeyguardUpdateMonitorLog public static LogBuffer provideKeyguardUpdateMonitorLogBuffer(LogBufferFactory factory) { - return factory.create("KeyguardUpdateMonitorLog", 200); + return factory.create("KeyguardUpdateMonitorLog", 400); } /** diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java index 6793f0163c43..43cf6231aaf0 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java @@ -36,6 +36,7 @@ import com.android.systemui.statusbar.phone.BarTransitions; import com.android.systemui.statusbar.phone.LightBarTransitionsController; import java.io.PrintWriter; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -75,15 +76,27 @@ public final class NavigationBarTransitions extends BarTransitions implements private List<DarkIntensityListener> mDarkIntensityListeners; private final Handler mHandler = Handler.getMain(); - private final IWallpaperVisibilityListener mWallpaperVisibilityListener = - new IWallpaperVisibilityListener.Stub() { + + static final class WallpaperVisibilityListener extends IWallpaperVisibilityListener.Stub { + private final WeakReference<NavigationBarTransitions> mSelf; + + WallpaperVisibilityListener(NavigationBarTransitions self) { + mSelf = new WeakReference<>(self); + } + @Override public void onWallpaperVisibilityChanged(boolean newVisibility, - int displayId) throws RemoteException { - mWallpaperVisible = newVisibility; - mHandler.post(() -> applyLightsOut(true, false)); + int displayId) throws RemoteException { + NavigationBarTransitions self = mSelf.get(); + if (self == null) { + return; + } + self.mWallpaperVisible = newVisibility; + self.mHandler.post(() -> self.applyLightsOut(true, false)); } - }; + } + + private final IWallpaperVisibilityListener mWallpaperVisibilityListener; @Inject public NavigationBarTransitions( @@ -91,6 +104,7 @@ public final class NavigationBarTransitions extends BarTransitions implements IWindowManager windowManagerService, LightBarTransitionsController.Factory lightBarTransitionsControllerFactory) { super(view, R.drawable.nav_background); + mView = view; mWindowManagerService = windowManagerService; mLightTransitionsController = lightBarTransitionsControllerFactory.create(this); @@ -98,6 +112,7 @@ public final class NavigationBarTransitions extends BarTransitions implements .getBoolean(R.bool.config_navigation_bar_enable_auto_dim_no_visible_wallpaper); mDarkIntensityListeners = new ArrayList(); + mWallpaperVisibilityListener = new WallpaperVisibilityListener(this); try { mWallpaperVisible = mWindowManagerService.registerWallpaperVisibilityListener( mWallpaperVisibilityListener, Display.DEFAULT_DISPLAY); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java index e0d780a5fcd5..afcf7a9ec66d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java @@ -16,6 +16,9 @@ package com.android.systemui.statusbar.window; +import static android.view.InsetsState.ITYPE_STATUS_BAR; +import static android.view.InsetsState.ITYPE_TOP_MANDATORY_GESTURES; +import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR; @@ -27,6 +30,7 @@ import static com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN; import android.content.Context; import android.content.res.Resources; +import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.Binder; @@ -36,6 +40,7 @@ import android.util.Log; import android.view.DisplayCutout; import android.view.Gravity; import android.view.IWindowManager; +import android.view.InsetsFrameProvider; import android.view.Surface; import android.view.View; import android.view.ViewGroup; @@ -221,6 +226,19 @@ public class StatusBarWindowController { lp.setTitle("StatusBar"); lp.packageName = mContext.getPackageName(); lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; + final InsetsFrameProvider gestureInsetsProvider = + new InsetsFrameProvider(ITYPE_TOP_MANDATORY_GESTURES); + final int safeTouchRegionHeight = mContext.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.display_cutout_touchable_region_size); + if (safeTouchRegionHeight > 0) { + gestureInsetsProvider.minimalInsetsSizeInDisplayCutoutSafe = + Insets.of(0, safeTouchRegionHeight, 0, 0); + } + lp.providedInsets = new InsetsFrameProvider[] { + new InsetsFrameProvider(ITYPE_STATUS_BAR), + new InsetsFrameProvider(ITYPE_TOP_TAPPABLE_ELEMENT), + gestureInsetsProvider + }; return lp; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java index b0cf0612b2d2..9bf27a26a682 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java @@ -19,6 +19,8 @@ package com.android.systemui.navigationbar; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -30,20 +32,25 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import android.content.res.Configuration; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; import android.util.SparseArray; import androidx.test.filters.SmallTest; +import com.android.dx.mockito.inline.extended.StaticMockitoSession; import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.model.SysUiState; import com.android.systemui.recents.OverviewProxyService; +import com.android.systemui.shared.recents.utilities.Utilities; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.AutoHideController; import com.android.systemui.statusbar.phone.LightBarController; @@ -72,11 +79,14 @@ public class NavigationBarControllerTest extends SysuiTestCase { private NavigationBarController mNavigationBarController; private NavigationBar mDefaultNavBar; private NavigationBar mSecondaryNavBar; + private StaticMockitoSession mMockitoSession; @Mock private CommandQueue mCommandQueue; @Mock private NavigationBarComponent.Factory mNavigationBarFactory; + @Mock + TaskbarDelegate mTaskbarDelegate; @Before public void setUp() { @@ -90,7 +100,7 @@ public class NavigationBarControllerTest extends SysuiTestCase { Dependency.get(Dependency.MAIN_HANDLER), mock(ConfigurationController.class), mock(NavBarHelper.class), - mock(TaskbarDelegate.class), + mTaskbarDelegate, mNavigationBarFactory, mock(StatusBarKeyguardViewManager.class), mock(DumpManager.class), @@ -100,6 +110,7 @@ public class NavigationBarControllerTest extends SysuiTestCase { Optional.of(mock(BackAnimation.class)), mock(FeatureFlags.class))); initializeNavigationBars(); + mMockitoSession = mockitoSession().mockStatic(Utilities.class).startMocking(); } private void initializeNavigationBars() { @@ -120,6 +131,7 @@ public class NavigationBarControllerTest extends SysuiTestCase { mNavigationBarController = null; mDefaultNavBar = null; mSecondaryNavBar = null; + mMockitoSession.finishMocking(); } @Test @@ -268,4 +280,22 @@ public class NavigationBarControllerTest extends SysuiTestCase { public void test3ButtonTaskbarFlagDisabledNoRegister() { verify(mCommandQueue, never()).addCallback(any(TaskbarDelegate.class)); } + + + @Test + public void testConfigurationChange_taskbarNotInitialized() { + Configuration configuration = mContext.getResources().getConfiguration(); + when(Utilities.isTablet(any())).thenReturn(true); + mNavigationBarController.onConfigChanged(configuration); + verify(mTaskbarDelegate, never()).onConfigurationChanged(configuration); + } + + @Test + public void testConfigurationChange_taskbarInitialized() { + Configuration configuration = mContext.getResources().getConfiguration(); + when(Utilities.isTablet(any())).thenReturn(true); + when(mTaskbarDelegate.isInitialized()).thenReturn(true); + mNavigationBarController.onConfigChanged(configuration); + verify(mTaskbarDelegate, times(1)).onConfigurationChanged(configuration); + } } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 00974e44e8bd..2be84d059286 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2036,9 +2036,11 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub if (resolvedUserIds.length != 1) { return Collections.emptyList(); } + final int callingUid = Binder.getCallingUid(); final long ident = Binder.clearCallingIdentity(); try { - return getInputMethodListLocked(resolvedUserIds[0], directBootAwareness); + return getInputMethodListLocked( + resolvedUserIds[0], directBootAwareness, callingUid); } finally { Binder.restoreCallingIdentity(ident); } @@ -2057,9 +2059,10 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub if (resolvedUserIds.length != 1) { return Collections.emptyList(); } + final int callingUid = Binder.getCallingUid(); final long ident = Binder.clearCallingIdentity(); try { - return getEnabledInputMethodListLocked(resolvedUserIds[0]); + return getEnabledInputMethodListLocked(resolvedUserIds[0], callingUid); } finally { Binder.restoreCallingIdentity(ident); } @@ -2090,12 +2093,14 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("ImfLock.class") private List<InputMethodInfo> getInputMethodListLocked(@UserIdInt int userId, - @DirectBootAwareness int directBootAwareness) { + @DirectBootAwareness int directBootAwareness, int callingUid) { final ArrayList<InputMethodInfo> methodList; + final InputMethodSettings settings; if (userId == mSettings.getCurrentUserId() && directBootAwareness == DirectBootAwareness.AUTO) { // Create a copy. methodList = new ArrayList<>(mMethodList); + settings = mSettings; } else { final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>(); methodList = new ArrayList<>(); @@ -2104,19 +2109,31 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub AdditionalSubtypeUtils.load(additionalSubtypeMap, userId); queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap, methodList, directBootAwareness); + settings = new InputMethodSettings(mContext, methodMap, userId, true /* copyOnWrite */); } + // filter caller's access to input methods + methodList.removeIf(imi -> + !canCallerAccessInputMethod(imi.getPackageName(), callingUid, userId, settings)); return methodList; } @GuardedBy("ImfLock.class") - private List<InputMethodInfo> getEnabledInputMethodListLocked(@UserIdInt int userId) { + private List<InputMethodInfo> getEnabledInputMethodListLocked(@UserIdInt int userId, + int callingUid) { + final ArrayList<InputMethodInfo> methodList; + final InputMethodSettings settings; if (userId == mSettings.getCurrentUserId()) { - return mSettings.getEnabledInputMethodListLocked(); + methodList = mSettings.getEnabledInputMethodListLocked(); + settings = mSettings; + } else { + final ArrayMap<String, InputMethodInfo> methodMap = queryMethodMapForUser(userId); + settings = new InputMethodSettings(mContext, methodMap, userId, true /* copyOnWrite */); + methodList = settings.getEnabledInputMethodListLocked(); } - final ArrayMap<String, InputMethodInfo> methodMap = queryMethodMapForUser(userId); - final InputMethodSettings settings = new InputMethodSettings(mContext, methodMap, userId, - true); - return settings.getEnabledInputMethodListLocked(); + // filter caller's access to input methods + methodList.removeIf(imi -> + !canCallerAccessInputMethod(imi.getPackageName(), callingUid, userId, settings)); + return methodList; } @GuardedBy("ImfLock.class") @@ -2155,10 +2172,11 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } synchronized (ImfLock.class) { + final int callingUid = Binder.getCallingUid(); final long ident = Binder.clearCallingIdentity(); try { return getEnabledInputMethodSubtypeListLocked(imiId, - allowsImplicitlyEnabledSubtypes, userId); + allowsImplicitlyEnabledSubtypes, userId, callingUid); } finally { Binder.restoreCallingIdentity(ident); } @@ -2167,7 +2185,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("ImfLock.class") private List<InputMethodSubtype> getEnabledInputMethodSubtypeListLocked(String imiId, - boolean allowsImplicitlyEnabledSubtypes, @UserIdInt int userId) { + boolean allowsImplicitlyEnabledSubtypes, @UserIdInt int userId, int callingUid) { if (userId == mSettings.getCurrentUserId()) { final InputMethodInfo imi; String selectedMethodId = getSelectedMethodIdLocked(); @@ -2176,7 +2194,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } else { imi = mMethodMap.get(imiId); } - if (imi == null) { + if (imi == null || !canCallerAccessInputMethod( + imi.getPackageName(), callingUid, userId, mSettings)) { return Collections.emptyList(); } return mSettings.getEnabledInputMethodSubtypeListLocked( @@ -2189,6 +2208,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } final InputMethodSettings settings = new InputMethodSettings(mContext, methodMap, userId, true); + if (!canCallerAccessInputMethod(imi.getPackageName(), callingUid, userId, settings)) { + return Collections.emptyList(); + } return settings.getEnabledInputMethodSubtypeListLocked( imi, allowsImplicitlyEnabledSubtypes); } @@ -5438,6 +5460,34 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub return true; } + /** + * Filter the access to the input method by rules of the package visibility. Return {@code true} + * if the given input method is the currently selected one or visible to the caller. + * + * @param targetPkgName The package name of input method to check. + * @param callingUid The caller that is going to access the input method. + * @param userId The user ID where the input method resides. + * @param settings The input method settings under the given user ID. + * @return {@code true} if caller is able to access the input method. + */ + private boolean canCallerAccessInputMethod(@NonNull String targetPkgName, int callingUid, + @UserIdInt int userId, @NonNull InputMethodSettings settings) { + final String methodId = settings.getSelectedInputMethod(); + final ComponentName selectedInputMethod = methodId != null + ? InputMethodUtils.convertIdToComponentName(methodId) : null; + if (selectedInputMethod != null + && selectedInputMethod.getPackageName().equals(targetPkgName)) { + return true; + } + final boolean canAccess = !mPackageManagerInternal.filterAppAccess( + targetPkgName, callingUid, userId); + if (DEBUG && !canAccess) { + Slog.d(TAG, "Input method " + targetPkgName + + " is not visible to the caller " + callingUid); + } + return canAccess; + } + private void publishLocalService() { LocalServices.addService(InputMethodManagerInternal.class, new LocalServiceImpl()); } @@ -5459,14 +5509,15 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @Override public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) { synchronized (ImfLock.class) { - return getInputMethodListLocked(userId, DirectBootAwareness.AUTO); + return getInputMethodListLocked(userId, DirectBootAwareness.AUTO, + Process.SYSTEM_UID); } } @Override public List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) { synchronized (ImfLock.class) { - return getEnabledInputMethodListLocked(userId); + return getEnabledInputMethodListLocked(userId, Process.SYSTEM_UID); } } @@ -6096,8 +6147,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub try (PrintWriter pr = shellCommand.getOutPrintWriter()) { for (int userId : userIds) { final List<InputMethodInfo> methods = all - ? getInputMethodListLocked(userId, DirectBootAwareness.AUTO) - : getEnabledInputMethodListLocked(userId); + ? getInputMethodListLocked( + userId, DirectBootAwareness.AUTO, Process.SHELL_UID) + : getEnabledInputMethodListLocked(userId, Process.SHELL_UID); if (userIds.length > 1) { pr.print("User #"); pr.print(userId); diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java index d12f1131acbe..c7ff8caf176b 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java @@ -20,11 +20,13 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserHandleAware; import android.annotation.UserIdInt; +import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; +import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.os.Build; import android.os.UserHandle; @@ -998,4 +1000,16 @@ final class InputMethodUtils { } return new int[]{sourceUserId}; } + + /** + * Convert the input method ID to a component name + * + * @param id A unique ID for this input method. + * @return The component name of the input method. + * @see InputMethodInfo#computeId(ResolveInfo) + */ + @Nullable + public static ComponentName convertIdToComponentName(@NonNull String id) { + return ComponentName.unflattenFromString(id); + } } diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java index 66bdadb185c1..ab69c3426d04 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java @@ -333,16 +333,25 @@ public class SyntheticPasswordManager { byte scryptLogP; public int credentialType; byte[] salt; - // If Weaver is available, then this field is empty. Otherwise, it is the Gatekeeper - // password handle that resulted from enrolling the hashed LSKF. + // This is the Gatekeeper password handle that resulted from enrolling the stretched LSKF, + // when applicable. This field isn't used if Weaver is available, or in new protectors when + // the LSKF is empty. public byte[] passwordHandle; - public static PasswordData create(int passwordType) { + public static PasswordData create(int credentialType) { PasswordData result = new PasswordData(); - result.scryptLogN = PASSWORD_SCRYPT_LOG_N; - result.scryptLogR = PASSWORD_SCRYPT_LOG_R; - result.scryptLogP = PASSWORD_SCRYPT_LOG_P; - result.credentialType = passwordType; + if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) { + // When the LSKF is empty, scrypt provides no security benefit, so just use the + // minimum parameters (N=2, r=1, p=1). + result.scryptLogN = 1; + result.scryptLogR = 0; + result.scryptLogP = 0; + } else { + result.scryptLogN = PASSWORD_SCRYPT_LOG_N; + result.scryptLogR = PASSWORD_SCRYPT_LOG_R; + result.scryptLogP = PASSWORD_SCRYPT_LOG_P; + } + result.credentialType = credentialType; result.salt = secureRandom(PASSWORD_SALT_LENGTH); return result; } @@ -776,11 +785,12 @@ public class SyntheticPasswordManager { long protectorId = generateProtectorId(); PasswordData pwd = PasswordData.create(credential.getType()); byte[] stretchedLskf = stretchLskf(credential, pwd); - final long sid; + long sid = GateKeeper.INVALID_SECURE_USER_ID; final byte[] protectorSecret; if (isWeaverAvailable()) { - // Protector uses Weaver to verify the LSKF + // Weaver is available, so make the protector use it to verify the LSKF. Do this even + // if the LSKF is empty, as that gives us support for securely deleting the protector. int weaverSlot = getNextAvailableWeaverSlot(); Slog.i(TAG, "Weaver enroll password to slot " + weaverSlot + " for user " + userId); byte[] weaverSecret = weaverEnroll(weaverSlot, stretchedLskfToWeaverKey(stretchedLskf), @@ -794,33 +804,34 @@ public class SyntheticPasswordManager { // No need to pass in quality since the credential type already encodes sufficient info synchronizeWeaverFrpPassword(pwd, 0, userId, weaverSlot); - pwd.passwordHandle = null; - sid = GateKeeper.INVALID_SECURE_USER_ID; protectorSecret = transformUnderWeaverSecret(stretchedLskf, weaverSecret); } else { - // Protector uses Gatekeeper to verify the LSKF - - // In case GK enrollment leaves persistent state around (in RPMB), this will nuke them - // to prevent them from accumulating and causing problems. - try { - gatekeeper.clearSecureUserId(fakeUserId(userId)); - } catch (RemoteException ignore) { - Slog.w(TAG, "Failed to clear SID from gatekeeper"); - } - GateKeeperResponse response; - try { - response = gatekeeper.enroll(fakeUserId(userId), null, null, - stretchedLskfToGkPassword(stretchedLskf)); - } catch (RemoteException e) { - throw new IllegalStateException("Failed to enroll LSKF for new SP protector for " - + "user " + userId, e); - } - if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) { - throw new IllegalStateException("Failed to enroll LSKF for new SP protector for " - + "user " + userId); + // Weaver is unavailable, so make the protector use Gatekeeper to verify the LSKF + // instead. However, skip Gatekeeper when the LSKF is empty, since it wouldn't give any + // benefit in that case as Gatekeeper isn't expected to provide secure deletion. + if (!credential.isNone()) { + // In case GK enrollment leaves persistent state around (in RPMB), this will nuke + // them to prevent them from accumulating and causing problems. + try { + gatekeeper.clearSecureUserId(fakeUserId(userId)); + } catch (RemoteException ignore) { + Slog.w(TAG, "Failed to clear SID from gatekeeper"); + } + GateKeeperResponse response; + try { + response = gatekeeper.enroll(fakeUserId(userId), null, null, + stretchedLskfToGkPassword(stretchedLskf)); + } catch (RemoteException e) { + throw new IllegalStateException("Failed to enroll LSKF for new SP protector" + + " for user " + userId, e); + } + if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) { + throw new IllegalStateException("Failed to enroll LSKF for new SP protector" + + " for user " + userId); + } + pwd.passwordHandle = response.getPayload(); + sid = sidFromPasswordHandle(pwd.passwordHandle); } - pwd.passwordHandle = response.getPayload(); - sid = sidFromPasswordHandle(pwd.passwordHandle); protectorSecret = transformUnderSecdiscardable(stretchedLskf, createSecdiscardable(protectorId, userId)); // No need to pass in quality since the credential type already encodes sufficient info @@ -1049,7 +1060,7 @@ public class SyntheticPasswordManager { byte[] stretchedLskf = stretchLskf(credential, pwd); final byte[] protectorSecret; - final long sid; + long sid = GateKeeper.INVALID_SECURE_USER_ID; int weaverSlot = loadWeaverSlot(protectorId, userId); if (weaverSlot != INVALID_WEAVER_SLOT) { // Protector uses Weaver to verify the LSKF @@ -1062,54 +1073,62 @@ public class SyntheticPasswordManager { if (result.gkResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) { return result; } - sid = GateKeeper.INVALID_SECURE_USER_ID; protectorSecret = transformUnderWeaverSecret(stretchedLskf, result.gkResponse.getGatekeeperHAT()); } else { - // Protector uses Gatekeeper to verify the LSKF - byte[] gkPassword = stretchedLskfToGkPassword(stretchedLskf); - GateKeeperResponse response; - try { - response = gatekeeper.verifyChallenge(fakeUserId(userId), 0L, - pwd.passwordHandle, gkPassword); - } catch (RemoteException e) { - Slog.e(TAG, "gatekeeper verify failed", e); - result.gkResponse = VerifyCredentialResponse.ERROR; - return result; - } - int responseCode = response.getResponseCode(); - if (responseCode == GateKeeperResponse.RESPONSE_OK) { - result.gkResponse = VerifyCredentialResponse.OK; - if (response.getShouldReEnroll()) { - GateKeeperResponse reenrollResponse; - try { - reenrollResponse = gatekeeper.enroll(fakeUserId(userId), - pwd.passwordHandle, gkPassword, gkPassword); - } catch (RemoteException e) { - Slog.w(TAG, "Fail to invoke gatekeeper.enroll", e); - reenrollResponse = GateKeeperResponse.ERROR; - // continue the flow anyway - } - if (reenrollResponse.getResponseCode() == GateKeeperResponse.RESPONSE_OK) { - pwd.passwordHandle = reenrollResponse.getPayload(); - // Use the reenrollment opportunity to update credential type - // (getting rid of CREDENTIAL_TYPE_PASSWORD_OR_PIN) - pwd.credentialType = credential.getType(); - saveState(PASSWORD_DATA_NAME, pwd.toBytes(), protectorId, userId); - synchronizeFrpPassword(pwd, 0, userId); - } else { - Slog.w(TAG, "Fail to re-enroll user password for user " + userId); - // continue the flow anyway + // Weaver is unavailable, so the protector uses Gatekeeper to verify the LSKF, unless + // the LSKF is empty in which case Gatekeeper might not have been used at all. + if (pwd.passwordHandle == null) { + if (!credential.isNone()) { + Slog.e(TAG, "Missing Gatekeeper password handle for nonempty LSKF"); + result.gkResponse = VerifyCredentialResponse.ERROR; + return result; + } + } else { + byte[] gkPassword = stretchedLskfToGkPassword(stretchedLskf); + GateKeeperResponse response; + try { + response = gatekeeper.verifyChallenge(fakeUserId(userId), 0L, + pwd.passwordHandle, gkPassword); + } catch (RemoteException e) { + Slog.e(TAG, "gatekeeper verify failed", e); + result.gkResponse = VerifyCredentialResponse.ERROR; + return result; + } + int responseCode = response.getResponseCode(); + if (responseCode == GateKeeperResponse.RESPONSE_OK) { + result.gkResponse = VerifyCredentialResponse.OK; + if (response.getShouldReEnroll()) { + GateKeeperResponse reenrollResponse; + try { + reenrollResponse = gatekeeper.enroll(fakeUserId(userId), + pwd.passwordHandle, gkPassword, gkPassword); + } catch (RemoteException e) { + Slog.w(TAG, "Fail to invoke gatekeeper.enroll", e); + reenrollResponse = GateKeeperResponse.ERROR; + // continue the flow anyway + } + if (reenrollResponse.getResponseCode() == GateKeeperResponse.RESPONSE_OK) { + pwd.passwordHandle = reenrollResponse.getPayload(); + // Use the reenrollment opportunity to update credential type + // (getting rid of CREDENTIAL_TYPE_PASSWORD_OR_PIN) + pwd.credentialType = credential.getType(); + saveState(PASSWORD_DATA_NAME, pwd.toBytes(), protectorId, userId); + synchronizeFrpPassword(pwd, 0, userId); + } else { + Slog.w(TAG, "Fail to re-enroll user password for user " + userId); + // continue the flow anyway + } } + } else if (responseCode == GateKeeperResponse.RESPONSE_RETRY) { + result.gkResponse = VerifyCredentialResponse.fromTimeout(response.getTimeout()); + return result; + } else { + result.gkResponse = VerifyCredentialResponse.ERROR; + return result; } - } else if (responseCode == GateKeeperResponse.RESPONSE_RETRY) { - result.gkResponse = VerifyCredentialResponse.fromTimeout(response.getTimeout()); - return result; - } else { - result.gkResponse = VerifyCredentialResponse.ERROR; - return result; + sid = sidFromPasswordHandle(pwd.passwordHandle); } - sid = sidFromPasswordHandle(pwd.passwordHandle); protectorSecret = transformUnderSecdiscardable(stretchedLskf, loadSecdiscardable(protectorId, userId)); } @@ -1463,7 +1482,8 @@ public class SyntheticPasswordManager { return result; } - private int fakeUserId(int userId) { + @VisibleForTesting + static int fakeUserId(int userId) { return 100000 + userId; } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index b91d9433f3b6..442777a20281 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -28,8 +28,6 @@ import static android.view.InsetsState.ITYPE_LEFT_GESTURES; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_RIGHT_GESTURES; import static android.view.InsetsState.ITYPE_STATUS_BAR; -import static android.view.InsetsState.ITYPE_TOP_MANDATORY_GESTURES; -import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT; import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS; import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; @@ -118,7 +116,6 @@ import android.util.ArraySet; import android.util.PrintWriterPrinter; import android.util.Slog; import android.util.SparseArray; -import android.view.DisplayCutout; import android.view.DisplayInfo; import android.view.Gravity; import android.view.InsetsFlags; @@ -1150,24 +1147,6 @@ public class DisplayPolicy { break; case TYPE_STATUS_BAR: mStatusBar = win; - final TriConsumer<DisplayFrames, WindowContainer, Rect> gestureFrameProvider = - (displayFrames, windowContainer, rect) -> { - rect.bottom = rect.top + getStatusBarHeight(displayFrames); - final DisplayCutout cutout = - displayFrames.mInsetsState.getDisplayCutout(); - if (cutout != null) { - final Rect top = cutout.getBoundingRectTop(); - if (!top.isEmpty()) { - rect.bottom = Math.max(rect.bottom, - top.bottom + mDisplayCutoutTouchableRegionSize); - } - } - }; - mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, win, null); - mDisplayContent.setInsetProvider( - ITYPE_TOP_MANDATORY_GESTURES, win, gestureFrameProvider); - mDisplayContent.setInsetProvider(ITYPE_TOP_TAPPABLE_ELEMENT, win, null); - mInsetsSourceWindowsExceptIme.add(win); break; case TYPE_NAVIGATION_BAR: mNavigationBar = win; @@ -1185,7 +1164,8 @@ public class DisplayPolicy { displayFrames.mUnrestricted, win.getBounds(), displayFrames.mDisplayCutoutSafe, inOutFrame, provider.source, - provider.insetsSize, lp.privateFlags); + provider.insetsSize, lp.privateFlags, + provider.minimalInsetsSizeInDisplayCutoutSafe); } } inOutFrame.inset(win.mGivenContentInsets); @@ -1231,85 +1211,91 @@ public class DisplayPolicy { mInsetsSourceWindowsExceptIme.add(win); if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar); break; - default: - if (attrs.providedInsets != null) { - for (int i = attrs.providedInsets.length - 1; i >= 0; i--) { - final InsetsFrameProvider provider = attrs.providedInsets[i]; - switch (provider.type) { - case ITYPE_STATUS_BAR: - mStatusBarAlt = win; - mStatusBarAltPosition = getAltBarPosition(attrs); - break; - case ITYPE_NAVIGATION_BAR: - mNavigationBarAlt = win; - mNavigationBarAltPosition = getAltBarPosition(attrs); - break; - case ITYPE_CLIMATE_BAR: - mClimateBarAlt = win; - mClimateBarAltPosition = getAltBarPosition(attrs); - break; - case ITYPE_EXTRA_NAVIGATION_BAR: - mExtraNavBarAlt = win; - mExtraNavBarAltPosition = getAltBarPosition(attrs); - break; + } + // TODO(b/239145252): Temporarily skip the navigation bar as it is still with the hard-coded + // logic. + if (attrs.providedInsets != null && attrs.type != TYPE_NAVIGATION_BAR) { + for (int i = attrs.providedInsets.length - 1; i >= 0; i--) { + final InsetsFrameProvider provider = attrs.providedInsets[i]; + switch (provider.type) { + case ITYPE_STATUS_BAR: + if (attrs.type != TYPE_STATUS_BAR) { + mStatusBarAlt = win; + mStatusBarAltPosition = getAltBarPosition(attrs); } - // The index of the provider and corresponding insets types cannot change at - // runtime as ensured in WMS. Make use of the index in the provider directly - // to access the latest provided size at runtime. - final int index = i; - final TriConsumer<DisplayFrames, WindowContainer, Rect> frameProvider = - provider.insetsSize != null - ? (displayFrames, windowContainer, inOutFrame) -> { - inOutFrame.inset(win.mGivenContentInsets); + break; + case ITYPE_NAVIGATION_BAR: + if (attrs.type != TYPE_NAVIGATION_BAR) { + mNavigationBarAlt = win; + mNavigationBarAltPosition = getAltBarPosition(attrs); + } + break; + case ITYPE_CLIMATE_BAR: + mClimateBarAlt = win; + mClimateBarAltPosition = getAltBarPosition(attrs); + break; + case ITYPE_EXTRA_NAVIGATION_BAR: + mExtraNavBarAlt = win; + mExtraNavBarAltPosition = getAltBarPosition(attrs); + break; + } + // The index of the provider and corresponding insets types cannot change at + // runtime as ensured in WMS. Make use of the index in the provider directly + // to access the latest provided size at runtime. + final int index = i; + final TriConsumer<DisplayFrames, WindowContainer, Rect> frameProvider = + provider.insetsSize != null + ? (displayFrames, windowContainer, inOutFrame) -> { + inOutFrame.inset(win.mGivenContentInsets); + final LayoutParams lp = + win.mAttrs.forRotation(displayFrames.mRotation); + final InsetsFrameProvider ifp = + win.mAttrs.forRotation(displayFrames.mRotation) + .providedInsets[index]; + InsetsFrameProvider.calculateInsetsFrame( + displayFrames.mUnrestricted, + windowContainer.getBounds(), + displayFrames.mDisplayCutoutSafe, + inOutFrame, ifp.source, + ifp.insetsSize, lp.privateFlags, + ifp.minimalInsetsSizeInDisplayCutoutSafe); + } : null; + final InsetsFrameProvider.InsetsSizeOverride[] overrides = + provider.insetsSizeOverrides; + final SparseArray<TriConsumer<DisplayFrames, WindowContainer, Rect>> + overrideProviders; + if (overrides != null) { + overrideProviders = new SparseArray<>(); + for (int j = overrides.length - 1; j >= 0; j--) { + final int overrideIndex = j; + final TriConsumer<DisplayFrames, WindowContainer, Rect> + overrideFrameProvider = + (displayFrames, windowContainer, inOutFrame) -> { final LayoutParams lp = - win.mAttrs.forRotation(displayFrames.mRotation); + win.mAttrs.forRotation( + displayFrames.mRotation); final InsetsFrameProvider ifp = - win.mAttrs.forRotation(displayFrames.mRotation) - .providedInsets[index]; + win.mAttrs.providedInsets[index]; InsetsFrameProvider.calculateInsetsFrame( displayFrames.mUnrestricted, windowContainer.getBounds(), displayFrames.mDisplayCutoutSafe, inOutFrame, ifp.source, - ifp.insetsSize, lp.privateFlags); - } : null; - final InsetsFrameProvider.InsetsSizeOverride[] overrides = - provider.insetsSizeOverrides; - final SparseArray<TriConsumer<DisplayFrames, WindowContainer, Rect>> - overrideProviders; - if (overrides != null) { - overrideProviders = new SparseArray<>(); - for (int j = overrides.length - 1; j >= 0; j--) { - final int overrideIndex = j; - final TriConsumer<DisplayFrames, WindowContainer, Rect> - overrideFrameProvider = - (displayFrames, windowContainer, inOutFrame) -> { - final LayoutParams lp = - win.mAttrs.forRotation( - displayFrames.mRotation); - final InsetsFrameProvider ifp = - win.mAttrs.providedInsets[index]; - InsetsFrameProvider.calculateInsetsFrame( - displayFrames.mUnrestricted, - windowContainer.getBounds(), - displayFrames.mDisplayCutoutSafe, - inOutFrame, ifp.source, - ifp.insetsSizeOverrides[ - overrideIndex].insetsSize, - lp.privateFlags); - }; - overrideProviders.put(overrides[j].windowType, - overrideFrameProvider); - } - } else { - overrideProviders = null; - } - mDisplayContent.setInsetProvider(provider.type, win, frameProvider, - overrideProviders); - mInsetsSourceWindowsExceptIme.add(win); + ifp.insetsSizeOverrides[ + overrideIndex].insetsSize, + lp.privateFlags, + null); + }; + overrideProviders.put(overrides[j].windowType, + overrideFrameProvider); } + } else { + overrideProviders = null; } - break; + mDisplayContent.setInsetProvider(provider.type, win, frameProvider, + overrideProviders); + mInsetsSourceWindowsExceptIme.add(win); + } } } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java index 5e6cccc07983..1e67c120b6e0 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java @@ -75,15 +75,34 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } @Test - public void testLskfBasedProtector() throws RemoteException { + public void testNoneLskfBasedProtector() throws RemoteException { + final int USER_ID = 10; + MockSyntheticPasswordManager manager = new MockSyntheticPasswordManager(mContext, mStorage, + mGateKeeperService, mUserManager, mPasswordSlotManager); + SyntheticPassword sp = manager.newSyntheticPassword(USER_ID); + assertFalse(lskfGatekeeperHandleExists(USER_ID)); + long protectorId = manager.createLskfBasedProtector(mGateKeeperService, + LockscreenCredential.createNone(), sp, USER_ID); + assertFalse(lskfGatekeeperHandleExists(USER_ID)); + + AuthenticationResult result = manager.unlockLskfBasedProtector(mGateKeeperService, + protectorId, LockscreenCredential.createNone(), USER_ID, null); + assertArrayEquals(result.syntheticPassword.deriveKeyStorePassword(), + sp.deriveKeyStorePassword()); + } + + @Test + public void testNonNoneLskfBasedProtector() throws RemoteException { final int USER_ID = 10; final LockscreenCredential password = newPassword("user-password"); final LockscreenCredential badPassword = newPassword("bad-password"); MockSyntheticPasswordManager manager = new MockSyntheticPasswordManager(mContext, mStorage, mGateKeeperService, mUserManager, mPasswordSlotManager); SyntheticPassword sp = manager.newSyntheticPassword(USER_ID); + assertFalse(lskfGatekeeperHandleExists(USER_ID)); long protectorId = manager.createLskfBasedProtector(mGateKeeperService, password, sp, USER_ID); + assertTrue(lskfGatekeeperHandleExists(USER_ID)); AuthenticationResult result = manager.unlockLskfBasedProtector(mGateKeeperService, protectorId, password, USER_ID, null); @@ -95,6 +114,10 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { assertNull(result.syntheticPassword); } + private boolean lskfGatekeeperHandleExists(int userId) throws RemoteException { + return mGateKeeperService.getSecureUserId(SyntheticPasswordManager.fakeUserId(userId)) != 0; + } + private boolean hasSyntheticPassword(int userId) throws RemoteException { return mService.getLong(CURRENT_LSKF_BASED_PROTECTOR_ID_KEY, 0, userId) != 0; } @@ -430,6 +453,21 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } @Test + public void testPasswordData_scryptParams() { + // CREDENTIAL_TYPE_NONE should result in the minimum scrypt params being used. + PasswordData data = PasswordData.create(CREDENTIAL_TYPE_NONE); + assertEquals(1, data.scryptLogN); + assertEquals(0, data.scryptLogR); + assertEquals(0, data.scryptLogP); + + // Any other credential type should result in the real scrypt params being used. + data = PasswordData.create(CREDENTIAL_TYPE_PASSWORD); + assertTrue(data.scryptLogN > 1); + assertTrue(data.scryptLogR > 0); + assertTrue(data.scryptLogP > 0); + } + + @Test public void testPasswordData_serializeDeserialize() { PasswordData data = new PasswordData(); data.scryptLogN = 11; diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java index 041f298d4aa2..f2bc47dfd6e9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java @@ -21,6 +21,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_STATUS_BAR; +import static android.view.InsetsState.ITYPE_TOP_MANDATORY_GESTURES; +import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR; @@ -45,6 +47,7 @@ import static org.mockito.Mockito.verify; import android.app.StatusBarManager; import android.platform.test.annotations.Presubmit; +import android.view.InsetsFrameProvider; import android.view.InsetsSource; import android.view.InsetsSourceControl; import android.view.InsetsState; @@ -70,7 +73,7 @@ public class InsetsPolicyTest extends WindowTestsBase { @Test public void testControlsForDispatch_regular() { - addWindow(TYPE_STATUS_BAR, "statusBar"); + addStatusBar(); addWindow(TYPE_NAVIGATION_BAR, "navBar"); final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch(); @@ -82,7 +85,7 @@ public class InsetsPolicyTest extends WindowTestsBase { @Test public void testControlsForDispatch_multiWindowTaskVisible() { - addWindow(TYPE_STATUS_BAR, "statusBar"); + addStatusBar(); addWindow(TYPE_NAVIGATION_BAR, "navBar"); final WindowState win = createWindow(null, WINDOWING_MODE_MULTI_WINDOW, @@ -95,7 +98,7 @@ public class InsetsPolicyTest extends WindowTestsBase { @Test public void testControlsForDispatch_freeformTaskVisible() { - addWindow(TYPE_STATUS_BAR, "statusBar"); + addStatusBar(); addWindow(TYPE_NAVIGATION_BAR, "navBar"); final WindowState win = createWindow(null, WINDOWING_MODE_FREEFORM, @@ -108,8 +111,7 @@ public class InsetsPolicyTest extends WindowTestsBase { @Test public void testControlsForDispatch_forceStatusBarVisible() { - addWindow(TYPE_STATUS_BAR, "statusBar").mAttrs.privateFlags |= - PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR; + addStatusBar().mAttrs.privateFlags |= PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR; addWindow(TYPE_NAVIGATION_BAR, "navBar"); final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch(); @@ -123,7 +125,7 @@ public class InsetsPolicyTest extends WindowTestsBase { public void testControlsForDispatch_statusBarForceShowNavigation() { addWindow(TYPE_NOTIFICATION_SHADE, "notificationShade").mAttrs.privateFlags |= PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION; - addWindow(TYPE_STATUS_BAR, "statusBar"); + addStatusBar(); addWindow(TYPE_NAVIGATION_BAR, "navBar"); final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch(); @@ -152,7 +154,7 @@ public class InsetsPolicyTest extends WindowTestsBase { public void testControlsForDispatch_remoteInsetsControllerControlsBars_appHasNoControl() { mDisplayContent.setRemoteInsetsController(createDisplayWindowInsetsController()); mDisplayContent.getInsetsPolicy().setRemoteInsetsControllerControlsSystemBars(true); - addWindow(TYPE_STATUS_BAR, "statusBar"); + addStatusBar(); addWindow(TYPE_NAVIGATION_BAR, "navBar"); final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch(); @@ -163,7 +165,7 @@ public class InsetsPolicyTest extends WindowTestsBase { @Test public void testControlsForDispatch_topAppHidesStatusBar() { - addWindow(TYPE_STATUS_BAR, "statusBar"); + addStatusBar(); addWindow(TYPE_NAVIGATION_BAR, "navBar"); // Add a fullscreen (MATCH_PARENT x MATCH_PARENT) app window which hides status bar. @@ -256,7 +258,7 @@ public class InsetsPolicyTest extends WindowTestsBase { @SetupWindows(addWindows = W_ACTIVITY) @Test public void testShowTransientBars_bothCanBeTransient_appGetsBothFakeControls() { - final WindowState statusBar = addNonFocusableWindow(TYPE_STATUS_BAR, "statusBar"); + final WindowState statusBar = addStatusBar(); statusBar.setHasSurface(true); statusBar.getControllableInsetProvider().setServerVisible(true); final WindowState navBar = addNonFocusableWindow(TYPE_NAVIGATION_BAR, "navBar"); @@ -298,8 +300,7 @@ public class InsetsPolicyTest extends WindowTestsBase { @SetupWindows(addWindows = W_ACTIVITY) @Test public void testShowTransientBars_statusBarCanBeTransient_appGetsStatusBarFakeControl() { - addNonFocusableWindow(TYPE_STATUS_BAR, "statusBar") - .getControllableInsetProvider().getSource().setVisible(false); + addStatusBar().getControllableInsetProvider().getSource().setVisible(false); addNonFocusableWindow(TYPE_NAVIGATION_BAR, "navBar") .getControllableInsetProvider().setServerVisible(true); @@ -328,8 +329,8 @@ public class InsetsPolicyTest extends WindowTestsBase { @SetupWindows(addWindows = W_ACTIVITY) @Test public void testAbortTransientBars_bothCanBeAborted_appGetsBothRealControls() { - final InsetsSource statusBarSource = addNonFocusableWindow(TYPE_STATUS_BAR, "statusBar") - .getControllableInsetProvider().getSource(); + final InsetsSource statusBarSource = + addStatusBar().getControllableInsetProvider().getSource(); final InsetsSource navBarSource = addNonFocusableWindow(TYPE_NAVIGATION_BAR, "navBar") .getControllableInsetProvider().getSource(); statusBarSource.setVisible(false); @@ -381,8 +382,7 @@ public class InsetsPolicyTest extends WindowTestsBase { @Test public void testShowTransientBars_abortsWhenControlTargetChanges() { - addNonFocusableWindow(TYPE_STATUS_BAR, "statusBar") - .getControllableInsetProvider().getSource().setVisible(false); + addStatusBar().getControllableInsetProvider().getSource().setVisible(false); addNonFocusableWindow(TYPE_NAVIGATION_BAR, "navBar") .getControllableInsetProvider().getSource().setVisible(false); final WindowState app = addWindow(TYPE_APPLICATION, "app"); @@ -406,6 +406,18 @@ public class InsetsPolicyTest extends WindowTestsBase { return win; } + private WindowState addStatusBar() { + final WindowState win = createWindow(null, TYPE_STATUS_BAR, "statusBar"); + win.mAttrs.flags |= FLAG_NOT_FOCUSABLE; + win.mAttrs.providedInsets = new InsetsFrameProvider[] { + new InsetsFrameProvider(ITYPE_STATUS_BAR), + new InsetsFrameProvider(ITYPE_TOP_TAPPABLE_ELEMENT), + new InsetsFrameProvider(ITYPE_TOP_MANDATORY_GESTURES) + }; + mDisplayContent.getDisplayPolicy().addWindowLw(win, win.mAttrs); + return win; + } + private WindowState addWindow(int type, String name) { final WindowState win = createWindow(null, type, name); mDisplayContent.getDisplayPolicy().addWindowLw(win, win.mAttrs); diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index 54b33e9794b6..d59fce089292 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -26,6 +26,8 @@ import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS; import static android.view.InsetsState.ITYPE_STATUS_BAR; +import static android.view.InsetsState.ITYPE_TOP_MANDATORY_GESTURES; +import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT; import static android.view.Surface.ROTATION_0; import static android.view.Surface.ROTATION_180; import static android.view.Surface.ROTATION_270; @@ -84,6 +86,7 @@ import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import android.provider.DeviceConfig; import android.provider.DeviceConfig.Properties; +import android.view.InsetsFrameProvider; import android.view.InsetsVisibilities; import android.view.WindowManager; @@ -3079,6 +3082,11 @@ public class SizeCompatTests extends WindowTestsBase { attrs.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; attrs.setFitInsetsTypes(0 /* types */); + attrs.providedInsets = new InsetsFrameProvider[] { + new InsetsFrameProvider(ITYPE_STATUS_BAR), + new InsetsFrameProvider(ITYPE_TOP_TAPPABLE_ELEMENT), + new InsetsFrameProvider(ITYPE_TOP_MANDATORY_GESTURES) + }; final TestWindowState statusBar = new TestWindowState( displayContent.mWmService, mock(Session.class), new TestIWindow(), attrs, token); token.addWindow(statusBar); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index c597b46ff73f..40326e9ad7f6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -27,6 +27,9 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.os.Process.SYSTEM_UID; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; +import static android.view.InsetsState.ITYPE_STATUS_BAR; +import static android.view.InsetsState.ITYPE_TOP_MANDATORY_GESTURES; +import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT; import static android.view.View.VISIBLE; import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY; import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL; @@ -324,6 +327,11 @@ class WindowTestsBase extends SystemServiceTestsBase { mStatusBarWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; mStatusBarWindow.mAttrs.setFitInsetsTypes(0); + mStatusBarWindow.mAttrs.providedInsets = new InsetsFrameProvider[] { + new InsetsFrameProvider(ITYPE_STATUS_BAR), + new InsetsFrameProvider(ITYPE_TOP_TAPPABLE_ELEMENT), + new InsetsFrameProvider(ITYPE_TOP_MANDATORY_GESTURES) + }; } if (addAll || ArrayUtils.contains(requestedWindows, W_NOTIFICATION_SHADE)) { mNotificationShadeWindow = createCommonWindow(null, TYPE_NOTIFICATION_SHADE, diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java index 1e74451a8d4d..2d382a27d747 100644 --- a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java +++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java @@ -17,6 +17,7 @@ package com.android.server.translation; import static android.view.translation.TranslationManager.EXTRA_CAPABILITIES; +import static android.view.translation.TranslationManager.STATUS_SYNC_CALL_FAIL; import static android.view.translation.UiTranslationManager.EXTRA_PACKAGE_NAME; import static android.view.translation.UiTranslationManager.EXTRA_SOURCE_LOCALE; import static android.view.translation.UiTranslationManager.EXTRA_STATE; @@ -32,7 +33,9 @@ import android.annotation.SuppressLint; import android.app.Activity; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.Bundle; import android.os.IBinder; @@ -40,6 +43,7 @@ import android.os.IRemoteCallback; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; +import android.service.translation.TranslationService; import android.service.translation.TranslationServiceInfo; import android.util.ArrayMap; import android.util.ArraySet; @@ -156,12 +160,27 @@ final class TranslationManagerServiceImpl extends return null; } final ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName); + if (!isServiceAvailableForUser(serviceComponent)) { + if (mMaster.verbose) { + Slog.v(TAG, "ensureRemoteServiceLocked(): " + serviceComponent + + " is not available,"); + } + return null; + } mRemoteTranslationService = new RemoteTranslationService(getContext(), serviceComponent, mUserId, /* isInstantAllowed= */ false, mRemoteServiceCallback); } return mRemoteTranslationService; } + private boolean isServiceAvailableForUser(ComponentName serviceComponent) { + Intent intent = new Intent(TranslationService.SERVICE_INTERFACE) + .setComponent(serviceComponent); + final ResolveInfo resolveInfo = getContext().getPackageManager().resolveServiceAsUser( + intent, PackageManager.GET_SERVICES | PackageManager.GET_META_DATA, mUserId); + return resolveInfo != null && resolveInfo.serviceInfo != null; + } + @GuardedBy("mLock") void onTranslationCapabilitiesRequestLocked(@TranslationSpec.DataFormat int sourceFormat, @TranslationSpec.DataFormat int destFormat, @@ -170,6 +189,9 @@ final class TranslationManagerServiceImpl extends if (remoteService != null) { remoteService.onTranslationCapabilitiesRequest(sourceFormat, destFormat, resultReceiver); + } else { + Slog.v(TAG, "onTranslationCapabilitiesRequestLocked(): no remote service."); + resultReceiver.send(STATUS_SYNC_CALL_FAIL, null); } } @@ -184,10 +206,13 @@ final class TranslationManagerServiceImpl extends @GuardedBy("mLock") void onSessionCreatedLocked(@NonNull TranslationContext translationContext, int sessionId, - IResultReceiver resultReceiver) { + IResultReceiver resultReceiver) throws RemoteException { final RemoteTranslationService remoteService = ensureRemoteServiceLocked(); if (remoteService != null) { remoteService.onSessionCreated(translationContext, sessionId, resultReceiver); + } else { + Slog.v(TAG, "onSessionCreatedLocked(): no remote service."); + resultReceiver.send(STATUS_SYNC_CALL_FAIL, null); } } diff --git a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java index de70dcb9b29c..79ab009d3b92 100644 --- a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java +++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java @@ -27,6 +27,7 @@ import android.os.Binder; import android.os.Bundle; import android.os.PersistableBundle; import android.os.SystemProperties; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import java.io.PrintWriter; @@ -192,4 +193,59 @@ public final class TelephonyUtils { // This is the error case. The well-defined value for UNKNOWN is -1. return "UNKNOWN(" + state + ")"; } + + /** + * Convert display name source to string. + * + * @param source The display name source. + * @return The display name source in string format. + */ + @NonNull + public static String displayNameSourceToString( + @SubscriptionManager.SimDisplayNameSource int source) { + switch (source) { + case SubscriptionManager.NAME_SOURCE_UNKNOWN: return "UNKNOWN"; + case SubscriptionManager.NAME_SOURCE_CARRIER_ID: return "CARRIER_ID"; + case SubscriptionManager.NAME_SOURCE_SIM_SPN: return "SIM_SPN"; + case SubscriptionManager.NAME_SOURCE_USER_INPUT: return "USER_INPUT"; + case SubscriptionManager.NAME_SOURCE_CARRIER: return "CARRIER"; + case SubscriptionManager.NAME_SOURCE_SIM_PNN: return "SIM_PNN"; + default: + return "UNKNOWN(" + source + ")"; + } + } + + /** + * Convert subscription type to string. + * + * @param type The subscription type. + * @return The subscription type in string format. + */ + @NonNull + public static String subscriptionTypeToString(@SubscriptionManager.SubscriptionType int type) { + switch (type) { + case SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM: return "LOCAL_SIM"; + case SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM: return "REMOTE_SIM"; + default: + return "UNKNOWN(" + type + ")"; + } + } + + /** + * Convert usage setting to string. + * + * @param usageSetting Usage setting. + * @return The usage setting in string format. + */ + @NonNull + public static String usageSettingToString(@SubscriptionManager.UsageSetting int usageSetting) { + switch (usageSetting) { + case SubscriptionManager.USAGE_SETTING_UNKNOWN: return "UNKNOWN"; + case SubscriptionManager.USAGE_SETTING_DEFAULT: return "DEFAULT"; + case SubscriptionManager.USAGE_SETTING_VOICE_CENTRIC: return "VOICE_CENTRIC"; + case SubscriptionManager.USAGE_SETTING_DATA_CENTRIC: return "DATA_CENTRIC"; + default: + return "UNKNOWN(" + usageSetting + ")"; + } + } } diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java index 4d58b22080cd..0d3c80fd8887 100644 --- a/telephony/java/android/telephony/SubscriptionInfo.java +++ b/telephony/java/android/telephony/SubscriptionInfo.java @@ -96,13 +96,6 @@ public class SubscriptionInfo implements Parcelable { private final CharSequence mCarrierName; /** - * The subscription carrier id. - * - * @see TelephonyManager#getSimCarrierId() - */ - private final int mCarrierId; - - /** * The source of the {@link #mDisplayName}. */ @SimDisplayNameSource @@ -127,12 +120,6 @@ public class SubscriptionInfo implements Parcelable { private final int mDataRoaming; /** - * SIM icon bitmap cache. - */ - @Nullable - private Bitmap mIconBitmap; - - /** * Mobile Country Code. */ @Nullable @@ -157,15 +144,16 @@ public class SubscriptionInfo implements Parcelable { private final String[] mHplmns; /** - * ISO Country code for the subscription's provider. + * Whether the subscription is from eSIM. */ - @NonNull - private final String mCountryIso; + private final boolean mIsEmbedded; /** - * Whether the subscription is from eSIM. + * The string ID of the SIM card. It is the ICCID of the active profile for a UICC card and the + * EID for an eUICC card. */ - private final boolean mIsEmbedded; + @NonNull + private final String mCardString; /** * The access rules for this subscription, if it is embedded and defines any. This does not @@ -182,18 +170,6 @@ public class SubscriptionInfo implements Parcelable { private final UiccAccessRule[] mCarrierConfigAccessRules; /** - * The string ID of the SIM card. It is the ICCID of the active profile for a UICC card and the - * EID for an eUICC card. - */ - @NonNull - private final String mCardString; - - /** - * The card ID of the SIM card. This maps uniquely to {@link #mCardString}. - */ - private final int mCardId; - - /** * Whether the subscription is opportunistic. */ private final boolean mIsOpportunistic; @@ -207,18 +183,17 @@ public class SubscriptionInfo implements Parcelable { private final ParcelUuid mGroupUuid; /** - * A package name that specifies who created the group. Empty if not available. + * ISO Country code for the subscription's provider. */ @NonNull - private final String mGroupOwner; + private final String mCountryIso; /** - * Whether group of the subscription is disabled. This is only useful if it's a grouped - * opportunistic subscription. In this case, if all primary (non-opportunistic) subscriptions - * in the group are deactivated (unplugged pSIM or deactivated eSIM profile), we should disable - * this opportunistic subscription. + * The subscription carrier id. + * + * @see TelephonyManager#getSimCarrierId() */ - private final boolean mIsGroupDisabled; + private final int mCarrierId; /** * The profile class populated from the profile metadata if present. Otherwise, @@ -236,6 +211,12 @@ public class SubscriptionInfo implements Parcelable { private final int mType; /** + * A package name that specifies who created the group. Empty if not available. + */ + @NonNull + private final String mGroupOwner; + + /** * Whether uicc applications are configured to enable or disable. * By default it's true. */ @@ -252,6 +233,27 @@ public class SubscriptionInfo implements Parcelable { @UsageSetting private final int mUsageSetting; + // Below are the fields that do not exist in the database. + + /** + * SIM icon bitmap cache. + */ + @Nullable + private Bitmap mIconBitmap; + + /** + * The card ID of the SIM card. This maps uniquely to {@link #mCardString}. + */ + private final int mCardId; + + /** + * Whether group of the subscription is disabled. This is only useful if it's a grouped + * opportunistic subscription. In this case, if all primary (non-opportunistic) subscriptions + * in the group are deactivated (unplugged pSIM or deactivated eSIM profile), we should disable + * this opportunistic subscription. + */ + private final boolean mIsGroupDisabled; + /** * @hide * @@ -665,7 +667,8 @@ public class SubscriptionInfo implements Parcelable { */ @NonNull public List<String> getEhplmns() { - return mEhplmns == null ? Collections.emptyList() : Arrays.asList(mEhplmns); + return Collections.unmodifiableList(mEhplmns == null + ? Collections.emptyList() : Arrays.asList(mEhplmns)); } /** @@ -673,7 +676,8 @@ public class SubscriptionInfo implements Parcelable { */ @NonNull public List<String> getHplmns() { - return mHplmns == null ? Collections.emptyList() : Arrays.asList(mHplmns); + return Collections.unmodifiableList(mHplmns == null + ? Collections.emptyList() : Arrays.asList(mHplmns)); } /** @@ -777,7 +781,7 @@ public class SubscriptionInfo implements Parcelable { if (mCarrierConfigAccessRules != null) { merged.addAll(Arrays.asList(mCarrierConfigAccessRules)); } - return merged.isEmpty() ? null : merged; + return merged.isEmpty() ? null : Collections.unmodifiableList(merged); } /** @@ -957,69 +961,75 @@ public class SubscriptionInfo implements Parcelable { public String toString() { String iccIdToPrint = givePrintableIccid(mIccId); String cardStringToPrint = givePrintableIccid(mCardString); - return "{id=" + mId + " iccId=" + iccIdToPrint + " simSlotIndex=" + mSimSlotIndex - + " carrierId=" + mCarrierId + " displayName=" + mDisplayName - + " carrierName=" + mCarrierName + " nameSource=" + mDisplayNameSource - + " iconTint=" + mIconTint - + " number=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mNumber) - + " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc=" + mMcc - + " mnc=" + mMnc + " countryIso=" + mCountryIso + " isEmbedded=" + mIsEmbedded - + " nativeAccessRules=" + Arrays.toString(mNativeAccessRules) - + " cardString=" + cardStringToPrint + " cardId=" + mCardId + return "[SubscriptionInfo: id=" + mId + + " iccId=" + iccIdToPrint + + " simSlotIndex=" + mSimSlotIndex + " portIndex=" + mPortIndex - + " isOpportunistic=" + mIsOpportunistic + " groupUuid=" + mGroupUuid + + " isEmbedded=" + mIsEmbedded + + " carrierId=" + mCarrierId + + " displayName=" + mDisplayName + + " carrierName=" + mCarrierName + + " isOpportunistic=" + mIsOpportunistic + + " groupUuid=" + mGroupUuid + + " groupOwner=" + mGroupOwner + " isGroupDisabled=" + mIsGroupDisabled - + " profileClass=" + mProfileClass + + " displayNameSource=" + + TelephonyUtils.displayNameSourceToString(mDisplayNameSource) + + " iconTint=" + mIconTint + + " number=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mNumber) + + " dataRoaming=" + mDataRoaming + + " mcc=" + mMcc + + " mnc=" + mMnc + " ehplmns=" + Arrays.toString(mEhplmns) + " hplmns=" + Arrays.toString(mHplmns) - + " mType=" + mType - + " groupOwner=" + mGroupOwner + + " cardString=" + cardStringToPrint + + " cardId=" + mCardId + + " nativeAccessRules=" + Arrays.toString(mNativeAccessRules) + " carrierConfigAccessRules=" + Arrays.toString(mCarrierConfigAccessRules) + + " countryIso=" + mCountryIso + + " profileClass=" + mProfileClass + + " mType=" + TelephonyUtils.subscriptionTypeToString(mType) + " areUiccApplicationsEnabled=" + mAreUiccApplicationsEnabled - + " usageSetting=" + mUsageSetting + "}"; + + " usageSetting=" + TelephonyUtils.usageSettingToString(mUsageSetting) + + "]"; } @Override - public int hashCode() { - return Objects.hash(mId, mSimSlotIndex, mDisplayNameSource, mIconTint, mDataRoaming, - mIsEmbedded, mIsOpportunistic, mGroupUuid, mIccId, mNumber, mMcc, mMnc, mCountryIso, - mCardString, mCardId, mDisplayName, mCarrierName, - Arrays.hashCode(mNativeAccessRules), mIsGroupDisabled, mCarrierId, mProfileClass, - mGroupOwner, mAreUiccApplicationsEnabled, mPortIndex, mUsageSetting); + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SubscriptionInfo that = (SubscriptionInfo) o; + return mId == that.mId && mSimSlotIndex == that.mSimSlotIndex + && mDisplayNameSource == that.mDisplayNameSource && mIconTint == that.mIconTint + && mDataRoaming == that.mDataRoaming && mIsEmbedded == that.mIsEmbedded + && mIsOpportunistic == that.mIsOpportunistic && mCarrierId == that.mCarrierId + && mProfileClass == that.mProfileClass && mType == that.mType + && mAreUiccApplicationsEnabled == that.mAreUiccApplicationsEnabled + && mPortIndex == that.mPortIndex && mUsageSetting == that.mUsageSetting + && mCardId == that.mCardId && mIsGroupDisabled == that.mIsGroupDisabled + && mIccId.equals(that.mIccId) && mDisplayName.equals(that.mDisplayName) + && mCarrierName.equals(that.mCarrierName) && mNumber.equals(that.mNumber) + && Objects.equals(mMcc, that.mMcc) && Objects.equals(mMnc, + that.mMnc) && Arrays.equals(mEhplmns, that.mEhplmns) + && Arrays.equals(mHplmns, that.mHplmns) && mCardString.equals( + that.mCardString) && Arrays.equals(mNativeAccessRules, + that.mNativeAccessRules) && Arrays.equals(mCarrierConfigAccessRules, + that.mCarrierConfigAccessRules) && Objects.equals(mGroupUuid, that.mGroupUuid) + && mCountryIso.equals(that.mCountryIso) && mGroupOwner.equals(that.mGroupOwner); } @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; - SubscriptionInfo toCompare = (SubscriptionInfo) obj; - return mId == toCompare.mId - && mSimSlotIndex == toCompare.mSimSlotIndex - && mDisplayNameSource == toCompare.mDisplayNameSource - && mIconTint == toCompare.mIconTint - && mDataRoaming == toCompare.mDataRoaming - && mIsEmbedded == toCompare.mIsEmbedded - && mIsOpportunistic == toCompare.mIsOpportunistic - && mIsGroupDisabled == toCompare.mIsGroupDisabled - && mAreUiccApplicationsEnabled == toCompare.mAreUiccApplicationsEnabled - && mCarrierId == toCompare.mCarrierId - && Objects.equals(mGroupUuid, toCompare.mGroupUuid) - && Objects.equals(mIccId, toCompare.mIccId) - && Objects.equals(mNumber, toCompare.mNumber) - && Objects.equals(mMcc, toCompare.mMcc) - && Objects.equals(mMnc, toCompare.mMnc) - && Objects.equals(mCountryIso, toCompare.mCountryIso) - && Objects.equals(mCardString, toCompare.mCardString) - && Objects.equals(mCardId, toCompare.mCardId) - && mPortIndex == toCompare.mPortIndex - && Objects.equals(mGroupOwner, toCompare.mGroupOwner) - && TextUtils.equals(mDisplayName, toCompare.mDisplayName) - && TextUtils.equals(mCarrierName, toCompare.mCarrierName) - && Arrays.equals(mNativeAccessRules, toCompare.mNativeAccessRules) - && mProfileClass == toCompare.mProfileClass - && Arrays.equals(mEhplmns, toCompare.mEhplmns) - && Arrays.equals(mHplmns, toCompare.mHplmns) - && mUsageSetting == toCompare.mUsageSetting; + public int hashCode() { + int result = Objects.hash(mId, mIccId, mSimSlotIndex, mDisplayName, mCarrierName, + mDisplayNameSource, mIconTint, mNumber, mDataRoaming, mMcc, mMnc, mIsEmbedded, + mCardString, mIsOpportunistic, mGroupUuid, mCountryIso, mCarrierId, mProfileClass, + mType, mGroupOwner, mAreUiccApplicationsEnabled, mPortIndex, mUsageSetting, mCardId, + mIsGroupDisabled); + result = 31 * result + Arrays.hashCode(mEhplmns); + result = 31 * result + Arrays.hashCode(mHplmns); + result = 31 * result + Arrays.hashCode(mNativeAccessRules); + result = 31 * result + Arrays.hashCode(mCarrierConfigAccessRules); + return result; } /** @@ -1031,7 +1041,7 @@ public class SubscriptionInfo implements Parcelable { /** * The subscription id. */ - private int mId = 0; + private int mId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; /** * The ICCID of the SIM that is associated with this subscription, empty if unknown. @@ -1064,7 +1074,7 @@ public class SubscriptionInfo implements Parcelable { * The source of the display name. */ @SimDisplayNameSource - private int mDisplayNameSource = SubscriptionManager.NAME_SOURCE_CARRIER_ID; + private int mDisplayNameSource = SubscriptionManager.NAME_SOURCE_UNKNOWN; /** * The color to be used for tinting the icon when displaying to the user. @@ -1141,7 +1151,7 @@ public class SubscriptionInfo implements Parcelable { /** * The card ID of the SIM card which contains the subscription. */ - private int mCardId = -1; + private int mCardId = TelephonyManager.UNINITIALIZED_CARD_ID; /** * Whether the subscription is opportunistic or not. @@ -1205,7 +1215,7 @@ public class SubscriptionInfo implements Parcelable { /** * the port index of the Uicc card. */ - private int mPortIndex = 0; + private int mPortIndex = TelephonyManager.INVALID_PORT_INDEX; /** * Subscription's preferred usage setting. @@ -1433,9 +1443,9 @@ public class SubscriptionInfo implements Parcelable { } /** - * Set the ISO Country code for the subscription's provider. + * Set the ISO country code for the subscription's provider. * - * @param countryIso The ISO Country code for the subscription's provider. + * @param countryIso The ISO country code for the subscription's provider. * @return The builder. */ @NonNull @@ -1592,7 +1602,7 @@ public class SubscriptionInfo implements Parcelable { * Set the carrier certificates for this subscription that are saved in carrier configs. * This does not include access rules from the Uicc, whether embedded or non-embedded. * - * @param carrierConfigAccessRules The carrier certificates for this subscription + * @param carrierConfigAccessRules The carrier certificates for this subscription. * @return The builder. */ @NonNull diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 193c2c143f98..6189b49bcf79 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -589,6 +589,12 @@ public class SubscriptionManager { public static final String NAME_SOURCE = SimInfo.COLUMN_NAME_SOURCE; /** + * The name_source is unknown. (for initialization) + * @hide + */ + public static final int NAME_SOURCE_UNKNOWN = SimInfo.NAME_SOURCE_UNKNOWN; + + /** * The name_source is from the carrier id. * @hide */ @@ -623,6 +629,7 @@ public class SubscriptionManager { @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"NAME_SOURCE_"}, value = { + NAME_SOURCE_UNKNOWN, NAME_SOURCE_CARRIER_ID, NAME_SOURCE_SIM_SPN, NAME_SOURCE_USER_INPUT, diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt index a27b2da1a19e..f810fbb2e3ec 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt @@ -16,7 +16,7 @@ package com.android.server.wm.flicker.ime -import android.platform.test.annotations.FlakyTest +import android.platform.test.annotations.Presubmit import android.view.Surface import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.BaseTest @@ -47,6 +47,7 @@ open class ReOpenImeWindowTest(testSpec: FlickerTestParameter) : BaseTest(testSp /** {@inheritDoc} */ override val transition: FlickerBuilder.() -> Unit = { setup { + tapl.workspace.switchToOverview().dismissAllTasks() testApp.launchViaIntent(wmHelper) testApp.openIME(wmHelper) this.setRotation(testSpec.startRotation) @@ -61,7 +62,7 @@ open class ReOpenImeWindowTest(testSpec: FlickerTestParameter) : BaseTest(testSp } /** {@inheritDoc} */ - @FlakyTest(bugId = 251214932) + @Presubmit @Test override fun visibleLayersShownMoreThanOneConsecutiveEntry() { // depends on how much of the animation transactions are sent to SF at once @@ -79,23 +80,23 @@ open class ReOpenImeWindowTest(testSpec: FlickerTestParameter) : BaseTest(testSp } /** {@inheritDoc} */ - @FlakyTest(bugId = 251214932) + @Presubmit @Test override fun visibleWindowsShownMoreThanOneConsecutiveEntry() { val component = ComponentNameMatcher("", "RecentTaskScreenshotSurface") testSpec.assertWm { this.visibleWindowsShownMoreThanOneConsecutiveEntry( ignoreWindows = - listOf( - ComponentNameMatcher.SPLASH_SCREEN, - ComponentNameMatcher.SNAPSHOT, - component - ) + listOf( + ComponentNameMatcher.SPLASH_SCREEN, + ComponentNameMatcher.SNAPSHOT, + component + ) ) } } - @FlakyTest(bugId = 251214932) + @Presubmit @Test fun launcherWindowBecomesInvisible() { testSpec.assertWm { @@ -105,11 +106,11 @@ open class ReOpenImeWindowTest(testSpec: FlickerTestParameter) : BaseTest(testSp } } - @FlakyTest(bugId = 251214932) + @Presubmit @Test fun imeWindowIsAlwaysVisible() = testSpec.imeWindowIsAlwaysVisible() - @FlakyTest(bugId = 251214932) + @Presubmit @Test fun imeAppWindowIsAlwaysVisible() { // the app starts visible in live tile, and stays visible for the duration of entering @@ -119,13 +120,13 @@ open class ReOpenImeWindowTest(testSpec: FlickerTestParameter) : BaseTest(testSp testSpec.assertWm { this.isAppWindowVisible(testApp) } } - @FlakyTest(bugId = 251214932) + @Presubmit @Test fun imeLayerBecomesVisible() { testSpec.assertLayers { this.isVisible(ComponentNameMatcher.IME) } } - @FlakyTest(bugId = 251214932) + @Presubmit @Test fun appLayerReplacesLauncher() { testSpec.assertLayers { @@ -137,60 +138,6 @@ open class ReOpenImeWindowTest(testSpec: FlickerTestParameter) : BaseTest(testSp } } - @FlakyTest(bugId = 251214932) - @Test - override fun navBarLayerPositionAtStartAndEnd() { - super.navBarLayerPositionAtStartAndEnd() - } - - @FlakyTest(bugId = 251214932) - @Test - override fun navBarWindowIsAlwaysVisible() { - super.navBarWindowIsAlwaysVisible() - } - - @FlakyTest(bugId = 251214932) - @Test - override fun statusBarLayerIsVisibleAtStartAndEnd() { - super.statusBarLayerIsVisibleAtStartAndEnd() - } - - @FlakyTest(bugId = 251214932) - @Test - override fun entireScreenCovered() { - super.entireScreenCovered() - } - - @FlakyTest(bugId = 251214932) - @Test - override fun navBarLayerIsVisibleAtStartAndEnd() { - super.navBarLayerIsVisibleAtStartAndEnd() - } - - @FlakyTest(bugId = 251214932) - @Test - override fun statusBarLayerPositionAtStartAndEnd() { - super.statusBarLayerPositionAtStartAndEnd() - } - - @FlakyTest(bugId = 251214932) - @Test - override fun statusBarWindowIsAlwaysVisible() { - super.statusBarWindowIsAlwaysVisible() - } - - @FlakyTest(bugId = 251214932) - @Test - override fun taskBarLayerIsVisibleAtStartAndEnd() { - super.taskBarLayerIsVisibleAtStartAndEnd() - } - - @FlakyTest(bugId = 251214932) - @Test - override fun taskBarWindowIsAlwaysVisible() { - super.taskBarWindowIsAlwaysVisible() - } - companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt index 7ccfeb7f6edd..73e6d223f824 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt @@ -16,7 +16,7 @@ package com.android.server.wm.flicker.launch -import android.platform.test.annotations.Postsubmit +import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.RequiresDevice import android.view.Surface import com.android.server.wm.flicker.FlickerParametersRunnerFactory @@ -81,87 +81,101 @@ class OpenAppColdFromIcon(testSpec: FlickerTestParameter) : } /** {@inheritDoc} */ - @Postsubmit @Test override fun appWindowAsTopWindowAtEnd() = super.appWindowAsTopWindowAtEnd() + @FlakyTest(bugId = 240916028) + @Test + override fun appWindowAsTopWindowAtEnd() = super.appWindowAsTopWindowAtEnd() /** {@inheritDoc} */ - @Postsubmit + @FlakyTest(bugId = 240916028) @Test override fun appWindowReplacesLauncherAsTopWindow() = super.appWindowReplacesLauncherAsTopWindow() /** {@inheritDoc} */ - @Postsubmit @Test override fun appLayerBecomesVisible() = super.appLayerBecomesVisible() + @FlakyTest(bugId = 240916028) + @Test + override fun appLayerBecomesVisible() = super.appLayerBecomesVisible() /** {@inheritDoc} */ - @Postsubmit @Test override fun appLayerReplacesLauncher() = super.appLayerReplacesLauncher() + @FlakyTest(bugId = 240916028) + @Test + override fun appLayerReplacesLauncher() = super.appLayerReplacesLauncher() /** {@inheritDoc} */ - @Postsubmit @Test override fun appWindowBecomesTopWindow() = super.appWindowBecomesTopWindow() + @FlakyTest(bugId = 240916028) + @Test + override fun appWindowBecomesTopWindow() = super.appWindowBecomesTopWindow() /** {@inheritDoc} */ - @Postsubmit @Test override fun appWindowBecomesVisible() = super.appWindowBecomesVisible() + @FlakyTest(bugId = 240916028) + @Test + override fun appWindowBecomesVisible() = super.appWindowBecomesVisible() /** {@inheritDoc} */ - @Postsubmit @Test override fun entireScreenCovered() = super.entireScreenCovered() + @FlakyTest(bugId = 240916028) + @Test + override fun entireScreenCovered() = super.entireScreenCovered() /** {@inheritDoc} */ - @Postsubmit @Test override fun focusChanges() = super.focusChanges() + @FlakyTest(bugId = 240916028) @Test override fun focusChanges() = super.focusChanges() /** {@inheritDoc} */ - @Postsubmit + @FlakyTest(bugId = 240916028) @Test override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd() /** {@inheritDoc} */ - @Postsubmit + @FlakyTest(bugId = 240916028) @Test override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd() /** {@inheritDoc} */ - @Postsubmit + @FlakyTest(bugId = 240916028) @Test override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible() /** {@inheritDoc} */ - @Postsubmit + @FlakyTest(bugId = 240916028) @Test override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd() /** {@inheritDoc} */ - @Postsubmit + @FlakyTest(bugId = 240916028) @Test override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible() /** {@inheritDoc} */ - @Postsubmit + @FlakyTest(bugId = 240916028) @Test override fun statusBarLayerPositionAtStartAndEnd() = super.statusBarLayerPositionAtStartAndEnd() /** {@inheritDoc} */ - @Postsubmit + @FlakyTest(bugId = 240916028) @Test override fun statusBarLayerIsVisibleAtStartAndEnd() = super.statusBarLayerIsVisibleAtStartAndEnd() /** {@inheritDoc} */ - @Postsubmit + @FlakyTest(bugId = 240916028) @Test override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible() /** {@inheritDoc} */ - @Postsubmit + @FlakyTest(bugId = 240916028) @Test override fun visibleLayersShownMoreThanOneConsecutiveEntry() = super.visibleLayersShownMoreThanOneConsecutiveEntry() /** {@inheritDoc} */ - @Postsubmit + @FlakyTest(bugId = 240916028) @Test override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = super.visibleWindowsShownMoreThanOneConsecutiveEntry() /** {@inheritDoc} */ - @Postsubmit @Test override fun appWindowIsTopWindowAtEnd() = super.appWindowIsTopWindowAtEnd() + @FlakyTest(bugId = 240916028) + @Test + override fun appWindowIsTopWindowAtEnd() = super.appWindowIsTopWindowAtEnd() companion object { /** diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt index 46186bcb5edc..bc1f0d18d8f4 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt @@ -16,7 +16,6 @@ package com.android.server.wm.flicker.quickswitch -import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.Presubmit import android.platform.test.annotations.RequiresDevice import android.view.Surface @@ -104,7 +103,7 @@ open class QuickSwitchBetweenTwoAppsBackTest(testSpec: FlickerTestParameter) : B * Checks that the transition starts with [testApp2]'s layers filling/covering exactly the * entirety of the display. */ - @FlakyTest(bugId = 250520840) + @Presubmit @Test open fun startsWithApp2LayersCoverFullScreen() { testSpec.assertLayersStart { @@ -236,15 +235,6 @@ open class QuickSwitchBetweenTwoAppsBackTest(testSpec: FlickerTestParameter) : B } } - /** {@inheritDoc} */ - @Presubmit - @Test - override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd() - - @FlakyTest(bugId = 250518877) - @Test - override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd() - companion object { private var startDisplayBounds = Rect.EMPTY diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt index 7a1350e5bbfa..f988bb2f1bf1 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt @@ -23,6 +23,7 @@ import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled import com.android.server.wm.flicker.navBarWindowIsVisibleAtStartAndEnd +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.Assume import org.junit.Before import org.junit.FixMethodOrder @@ -61,8 +62,8 @@ open class QuickSwitchBetweenTwoAppsBackTest_ShellTransit(testSpec: FlickerTestP override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible() /** - * Checks that [ComponentMatcher.NAV_BAR] window is visible and above the app windows at the - * start and end of the WM trace + * Checks that [ComponentNameMatcher.NAV_BAR] window is visible and above the app windows at + * the start and end of the WM trace */ @Presubmit @Test @@ -71,8 +72,18 @@ open class QuickSwitchBetweenTwoAppsBackTest_ShellTransit(testSpec: FlickerTestP testSpec.navBarWindowIsVisibleAtStartAndEnd() } + /** {@inheritDoc} */ + @FlakyTest(bugId = 250520840) + @Test + override fun startsWithApp2LayersCoverFullScreen() = + super.startsWithApp2LayersCoverFullScreen() + @FlakyTest(bugId = 246284708) @Test override fun visibleLayersShownMoreThanOneConsecutiveEntry() = super.visibleLayersShownMoreThanOneConsecutiveEntry() + + @FlakyTest(bugId = 250518877) + @Test + override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd() } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt index 0a21044f6dda..7e4504bc7a48 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt @@ -16,7 +16,6 @@ package com.android.server.wm.flicker.quickswitch -import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.Presubmit import android.platform.test.annotations.RequiresDevice import android.view.Surface @@ -116,7 +115,7 @@ open class QuickSwitchBetweenTwoAppsForwardTest(testSpec: FlickerTestParameter) * Checks that the transition starts with [testApp1]'s layers filling/covering exactly the * entirety of the display. */ - @FlakyTest(bugId = 250522691) + @Presubmit @Test open fun startsWithApp1LayersCoverFullScreen() { testSpec.assertLayersStart { @@ -255,10 +254,6 @@ open class QuickSwitchBetweenTwoAppsForwardTest(testSpec: FlickerTestParameter) @Test override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd() - @FlakyTest(bugId = 250518877) - @Test - override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd() - companion object { private var startDisplayBounds = Rect.EMPTY diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest_ShellTransit.kt index 03647c9801c7..cc954ab6ee5d 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest_ShellTransit.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest_ShellTransit.kt @@ -23,6 +23,7 @@ import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled import com.android.server.wm.flicker.navBarWindowIsVisibleAtStartAndEnd +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.Assume import org.junit.Before import org.junit.FixMethodOrder @@ -62,8 +63,8 @@ open class QuickSwitchBetweenTwoAppsForwardTest_ShellTransit(testSpec: FlickerTe override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible() /** - * Checks that [ComponentMatcher.NAV_BAR] window is visible and above the app windows at the - * start and end of the WM trace + * Checks that [ComponentNameMatcher.NAV_BAR] window is visible and above the app windows at + * the start and end of the WM trace */ @Presubmit @Test @@ -76,4 +77,13 @@ open class QuickSwitchBetweenTwoAppsForwardTest_ShellTransit(testSpec: FlickerTe @Test override fun visibleLayersShownMoreThanOneConsecutiveEntry() = super.visibleLayersShownMoreThanOneConsecutiveEntry() + + @FlakyTest(bugId = 250518877) + @Test + override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd() + + @FlakyTest(bugId = 250522691) + @Test + override fun startsWithApp1LayersCoverFullScreen() = + super.startsWithApp1LayersCoverFullScreen() } diff --git a/tools/processors/immutability/Android.bp b/tools/processors/immutability/Android.bp index fe97a903bff8..2ce785f10a2c 100644 --- a/tools/processors/immutability/Android.bp +++ b/tools/processors/immutability/Android.bp @@ -67,6 +67,7 @@ java_test_host { "--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", "--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", ], + test_config_template: "AndroidTestTemplate.xml", } filegroup { diff --git a/tools/processors/immutability/AndroidTestTemplate.xml b/tools/processors/immutability/AndroidTestTemplate.xml new file mode 100644 index 000000000000..b9cf62f5ca5b --- /dev/null +++ b/tools/processors/immutability/AndroidTestTemplate.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2022 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<!-- This test config file is auto-generated. --> +<configuration description="Runs {MODULE}"> + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-unit-tests" /> + <option name="config-descriptor:metadata" key="component" value="{MODULE}" /> + + {EXTRA_CONFIGS} + + <test class="com.android.tradefed.testtype.IsolatedHostTest" > + <option name="jar" value="{MODULE}.jar" /> + <option name="java-flags" value="--add-modules=jdk.compiler"/> + <option name="java-flags" value="--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED"/> + <option name="java-flags" value="--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED"/> + <option name="java-flags" value="--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED"/> + <option name="java-flags" value="--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED"/> + </test> +</configuration> diff --git a/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt b/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt index 0fb062f280e3..0b619488c49c 100644 --- a/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt +++ b/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt @@ -39,7 +39,7 @@ fun main(args: Array<String>) { kotlin.system.exitProcess(2) } - val ancestorCollector = AncestorCollector(Opcodes.ASM7, null) + val ancestorCollector = AncestorCollector(Opcodes.ASM9, null) for (entry in zipFile.entries()) { if (entry.name.endsWith(".class")) { diff --git a/tools/traceinjection/src/com/android/traceinjection/TraceInjectionClassVisitor.java b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionClassVisitor.java index 863f976b8aff..67c5561f348d 100644 --- a/tools/traceinjection/src/com/android/traceinjection/TraceInjectionClassVisitor.java +++ b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionClassVisitor.java @@ -28,7 +28,7 @@ public class TraceInjectionClassVisitor extends ClassVisitor { private final TraceInjectionConfiguration mParams; public TraceInjectionClassVisitor(ClassVisitor classVisitor, TraceInjectionConfiguration params) { - super(Opcodes.ASM7, classVisitor); + super(Opcodes.ASM9, classVisitor); mParams = params; } diff --git a/tools/traceinjection/src/com/android/traceinjection/TraceInjectionMethodAdapter.java b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionMethodAdapter.java index c2bbddcb5668..91e987dc72ee 100644 --- a/tools/traceinjection/src/com/android/traceinjection/TraceInjectionMethodAdapter.java +++ b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionMethodAdapter.java @@ -61,7 +61,7 @@ public class TraceInjectionMethodAdapter extends AdviceAdapter { public TraceInjectionMethodAdapter(MethodVisitor methodVisitor, int access, String name, String descriptor, TraceInjectionConfiguration params) { - super(Opcodes.ASM7, methodVisitor, access, name, descriptor); + super(Opcodes.ASM9, methodVisitor, access, name, descriptor); mParams = params; mIsConstructor = "<init>".equals(name); } @@ -157,7 +157,7 @@ public class TraceInjectionMethodAdapter extends AdviceAdapter { class TracingAnnotationVisitor extends AnnotationVisitor { TracingAnnotationVisitor(AnnotationVisitor annotationVisitor) { - super(Opcodes.ASM7, annotationVisitor); + super(Opcodes.ASM9, annotationVisitor); } @Override |