diff options
91 files changed, 1369 insertions, 1131 deletions
diff --git a/PACKAGE_MANAGER_OWNERS b/PACKAGE_MANAGER_OWNERS new file mode 100644 index 000000000000..e4549b4de164 --- /dev/null +++ b/PACKAGE_MANAGER_OWNERS @@ -0,0 +1,3 @@ +chiuwinson@google.com +patb@google.com +schfan@google.com
\ No newline at end of file diff --git a/apex/media/framework/java/android/media/BaseMediaParceledListSlice.java b/apex/media/framework/java/android/media/BaseMediaParceledListSlice.java index fb666098301a..915f3f6a3fb0 100644 --- a/apex/media/framework/java/android/media/BaseMediaParceledListSlice.java +++ b/apex/media/framework/java/android/media/BaseMediaParceledListSlice.java @@ -43,7 +43,7 @@ import java.util.List; */ abstract class BaseMediaParceledListSlice<T> implements Parcelable { private static String TAG = "BaseMediaParceledListSlice"; - private static boolean DEBUG = false; + private static final boolean DEBUG = false; /* * TODO get this number from somewhere else. For now set it to a quarter of diff --git a/core/api/current.txt b/core/api/current.txt index f989d0621843..52e0daff0ec4 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -22672,7 +22672,7 @@ package android.media { field public static final String KEY_MAX_FPS_TO_ENCODER = "max-fps-to-encoder"; field public static final String KEY_MAX_HEIGHT = "max-height"; field public static final String KEY_MAX_INPUT_SIZE = "max-input-size"; - field public static final String KEY_MAX_OUTPUT_CHANNEL_COUNT = "max-output-channel_count"; + field public static final String KEY_MAX_OUTPUT_CHANNEL_COUNT = "max-output-channel-count"; field public static final String KEY_MAX_PTS_GAP_TO_ENCODER = "max-pts-gap-to-encoder"; field public static final String KEY_MAX_WIDTH = "max-width"; field public static final String KEY_MIME = "mime"; @@ -47696,6 +47696,10 @@ package android.view { field public static final int KEYCODE_CUT = 277; // 0x115 field public static final int KEYCODE_D = 32; // 0x20 field public static final int KEYCODE_DEL = 67; // 0x43 + field public static final int KEYCODE_DEMO_APP_1 = 301; // 0x12d + field public static final int KEYCODE_DEMO_APP_2 = 302; // 0x12e + field public static final int KEYCODE_DEMO_APP_3 = 303; // 0x12f + field public static final int KEYCODE_DEMO_APP_4 = 304; // 0x130 field public static final int KEYCODE_DPAD_CENTER = 23; // 0x17 field public static final int KEYCODE_DPAD_DOWN = 20; // 0x14 field public static final int KEYCODE_DPAD_DOWN_LEFT = 269; // 0x10d @@ -47727,6 +47731,10 @@ package android.view { field public static final int KEYCODE_F7 = 137; // 0x89 field public static final int KEYCODE_F8 = 138; // 0x8a field public static final int KEYCODE_F9 = 139; // 0x8b + field public static final int KEYCODE_FEATURED_APP_1 = 297; // 0x129 + field public static final int KEYCODE_FEATURED_APP_2 = 298; // 0x12a + field public static final int KEYCODE_FEATURED_APP_3 = 299; // 0x12b + field public static final int KEYCODE_FEATURED_APP_4 = 300; // 0x12c field public static final int KEYCODE_FOCUS = 80; // 0x50 field public static final int KEYCODE_FORWARD = 125; // 0x7d field public static final int KEYCODE_FORWARD_DEL = 112; // 0x70 @@ -47892,6 +47900,14 @@ package android.view { field public static final int KEYCODE_U = 49; // 0x31 field public static final int KEYCODE_UNKNOWN = 0; // 0x0 field public static final int KEYCODE_V = 50; // 0x32 + field public static final int KEYCODE_VIDEO_APP_1 = 289; // 0x121 + field public static final int KEYCODE_VIDEO_APP_2 = 290; // 0x122 + field public static final int KEYCODE_VIDEO_APP_3 = 291; // 0x123 + field public static final int KEYCODE_VIDEO_APP_4 = 292; // 0x124 + field public static final int KEYCODE_VIDEO_APP_5 = 293; // 0x125 + field public static final int KEYCODE_VIDEO_APP_6 = 294; // 0x126 + field public static final int KEYCODE_VIDEO_APP_7 = 295; // 0x127 + field public static final int KEYCODE_VIDEO_APP_8 = 296; // 0x128 field public static final int KEYCODE_VOICE_ASSIST = 231; // 0xe7 field public static final int KEYCODE_VOLUME_DOWN = 25; // 0x19 field public static final int KEYCODE_VOLUME_MUTE = 164; // 0xa4 diff --git a/core/api/system-current.txt b/core/api/system-current.txt index f92c36d488ad..a0f2d2393443 100755 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -1954,7 +1954,7 @@ package android.bluetooth { method public long getControllerIdleTimeMillis(); method public long getControllerRxTimeMillis(); method public long getControllerTxTimeMillis(); - method public long getTimeStamp(); + method public long getTimestampMillis(); method @NonNull public java.util.List<android.bluetooth.UidTraffic> getUidTraffic(); method public boolean isValid(); field public static final int BT_STACK_STATE_INVALID = 0; // 0x0 diff --git a/core/api/test-current.txt b/core/api/test-current.txt index e707b038e1b6..71ed8348d397 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -2785,7 +2785,7 @@ package android.view { method public static String actionToString(int); method public final void setDisplayId(int); field public static final int FLAG_IS_ACCESSIBILITY_EVENT = 2048; // 0x800 - field public static final int LAST_KEYCODE = 288; // 0x120 + field public static final int LAST_KEYCODE = 304; // 0x130 } public final class KeyboardShortcutGroup implements android.os.Parcelable { diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 8ea1f8315b89..40c19788ae5d 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -1925,39 +1925,6 @@ public final class SystemServiceRegistry { public abstract T createService() throws ServiceNotFoundException; } - /** - * Like StaticServiceFetcher, creates only one instance of the service per application, but when - * creating the service for the first time, passes it the application context of the creating - * application. - * - * TODO: Delete this once its only user (ConnectivityManager) is known to work well in the - * case where multiple application components each have their own ConnectivityManager object. - */ - static abstract class StaticApplicationContextServiceFetcher<T> implements ServiceFetcher<T> { - private T mCachedInstance; - - @Override - public final T getService(ContextImpl ctx) { - synchronized (StaticApplicationContextServiceFetcher.this) { - if (mCachedInstance == null) { - Context appContext = ctx.getApplicationContext(); - // If the application context is null, we're either in the system process or - // it's the application context very early in app initialization. In both these - // cases, the passed-in ContextImpl will not be freed, so it's safe to pass it - // to the service. http://b/27532714 . - try { - mCachedInstance = createService(appContext != null ? appContext : ctx); - } catch (ServiceNotFoundException e) { - onServiceNotFound(e); - } - } - return mCachedInstance; - } - } - - public abstract T createService(Context applicationContext) throws ServiceNotFoundException; - } - /** @hide */ public static void onServiceNotFound(ServiceNotFoundException e) { // We're mostly interested in tracking down long-lived core system diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index a53ef1badca7..b3fad21f2e44 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -108,7 +108,7 @@ import java.util.concurrent.TimeUnit; @SystemService(Context.WALLPAPER_SERVICE) public class WallpaperManager { private static String TAG = "WallpaperManager"; - private static boolean DEBUG = false; + private static final boolean DEBUG = false; private float mWallpaperXStep = -1; private float mWallpaperYStep = -1; private static final @NonNull RectF LOCAL_COLOR_BOUNDS = diff --git a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java index f371c6d78221..c17a7b4b3dfd 100644 --- a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java +++ b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java @@ -16,6 +16,7 @@ package android.bluetooth; +import android.annotation.ElapsedRealtimeLong; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; @@ -167,7 +168,7 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { /** * @return timestamp (real time elapsed in milliseconds since boot) of record creation */ - public long getTimeStamp() { + public @ElapsedRealtimeLong long getTimestampMillis() { return mTimestamp; } @@ -189,7 +190,7 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { } /** - * @return true if the record is valid + * @return true if the record Tx time, Rx time, and Idle time are more than 0. */ public boolean isValid() { return ((mControllerTxTimeMs >= 0) && (mControllerRxTimeMs >= 0) diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index e968052ff5cf..6e918bd6243d 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -1186,6 +1186,11 @@ public final class BluetoothDevice implements Parcelable, Attributable { mAttributionSource = attributionSource; } + /** {@hide} */ + public void prepareToEnterProcess(@NonNull AttributionSource attributionSource) { + setAttributionSource(attributionSource); + } + @Override public boolean equals(@Nullable Object o) { if (o instanceof BluetoothDevice) { diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java index b5df4db2460d..20152f3d2471 100644 --- a/core/java/android/bluetooth/BluetoothManager.java +++ b/core/java/android/bluetooth/BluetoothManager.java @@ -62,15 +62,15 @@ public final class BluetoothManager { private static final String TAG = "BluetoothManager"; private static final boolean DBG = false; - private static AttributionSource sAttributionSource = null; + private final AttributionSource mAttributionSource; private final BluetoothAdapter mAdapter; /** * @hide */ public BluetoothManager(Context context) { - sAttributionSource = resolveAttributionSource(context); - mAdapter = BluetoothAdapter.createAdapter(sAttributionSource); + mAttributionSource = resolveAttributionSource(context); + mAdapter = BluetoothAdapter.createAdapter(mAttributionSource); } /** {@hide} */ @@ -79,9 +79,6 @@ public final class BluetoothManager { if (context != null) { res = context.getAttributionSource(); } - else if (sAttributionSource != null) { - return sAttributionSource; - } if (res == null) { res = ActivityThread.currentAttributionSource(); } @@ -201,8 +198,8 @@ public final class BluetoothManager { IBluetoothGatt iGatt = managerService.getBluetoothGatt(); if (iGatt == null) return devices; devices = Attributable.setAttributionSource( - iGatt.getDevicesMatchingConnectionStates(states, sAttributionSource), - sAttributionSource); + iGatt.getDevicesMatchingConnectionStates(states, mAttributionSource), + mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 6446b44153ec..e838d93c6cdc 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -32,6 +32,7 @@ import android.annotation.SystemApi; import android.annotation.TestApi; import android.app.ActivityThread; import android.app.AppGlobals; +import android.bluetooth.BluetoothDevice; import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; @@ -11688,6 +11689,16 @@ public class Intent implements Parcelable, Cloneable { if (fromProtectedComponent) { mLocalFlags |= LOCAL_FLAG_FROM_PROTECTED_COMPONENT; } + + // Special attribution fix-up logic for any BluetoothDevice extras + // passed via Bluetooth intents + if (mAction != null && mAction.startsWith("android.bluetooth.") + && hasExtra(BluetoothDevice.EXTRA_DEVICE)) { + final BluetoothDevice device = getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + if (device != null) { + device.prepareToEnterProcess(source); + } + } } /** @hide */ diff --git a/core/java/android/content/OWNERS b/core/java/android/content/OWNERS index c7f92c9714f0..660368aeca14 100644 --- a/core/java/android/content/OWNERS +++ b/core/java/android/content/OWNERS @@ -2,11 +2,9 @@ per-file Context.java = * per-file ContextWrapper.java = * per-file Content* = file:/services/core/java/com/android/server/am/OWNERS -per-file IntentFilter.java = toddke@google.com -per-file IntentFilter.java = patb@google.com +per-file IntentFilter.java = file:/PACKAGE_MANAGER_OWNERS per-file IntentFilter.java = file:/services/core/java/com/android/server/am/OWNERS -per-file Intent.java = toddke@google.com -per-file Intent.java = patb@google.com +per-file Intent.java = file:/PACKAGE_MANAGER_OWNERS per-file Intent.java = file:/services/core/java/com/android/server/wm/OWNERS per-file Intent.java = file:/services/core/java/com/android/server/am/OWNERS per-file AutofillOptions* = file:/core/java/android/service/autofill/OWNERS diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING index 0d8fdcc4138f..cc4782ad4a79 100644 --- a/core/java/android/content/pm/TEST_MAPPING +++ b/core/java/android/content/pm/TEST_MAPPING @@ -1,6 +1,15 @@ { "imports": [ { + "path": "frameworks/base/services/tests/PackageManagerServiceTests" + }, + { + "path": "frameworks/base/services/tests/PackageManager" + }, + { + "path": "frameworks/base/services/tests/PackageManagerComponentOverrideTests" + }, + { "path": "cts/tests/tests/packageinstaller" }, { diff --git a/core/java/android/hardware/biometrics/BiometricOverlayConstants.java b/core/java/android/hardware/biometrics/BiometricOverlayConstants.java index 603b06ddabaa..065ae64a92ad 100644 --- a/core/java/android/hardware/biometrics/BiometricOverlayConstants.java +++ b/core/java/android/hardware/biometrics/BiometricOverlayConstants.java @@ -38,13 +38,16 @@ public interface BiometricOverlayConstants { int REASON_AUTH_KEYGUARD = 4; /** Non-specific usage (from FingerprintManager). */ int REASON_AUTH_OTHER = 5; + /** Usage from Settings. */ + int REASON_AUTH_SETTINGS = 6; @IntDef({REASON_UNKNOWN, REASON_ENROLL_FIND_SENSOR, REASON_ENROLL_ENROLLING, REASON_AUTH_BP, REASON_AUTH_KEYGUARD, - REASON_AUTH_OTHER}) + REASON_AUTH_OTHER, + REASON_AUTH_SETTINGS}) @Retention(RetentionPolicy.SOURCE) @interface ShowReason {} } diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 1d07a0330bc5..eb8f43e3d073 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -220,8 +220,10 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> { String networkId = null; boolean roaming = !snapshot.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); - boolean metered = !snapshot.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + boolean metered = !(snapshot.getNetworkCapabilities().hasCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_METERED) + || snapshot.getNetworkCapabilities().hasCapability( + NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)); final int oemManaged = getOemBitfield(snapshot.getNetworkCapabilities()); diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index d12ed8f1595e..1460cb251c72 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -832,13 +832,45 @@ public class KeyEvent extends InputEvent implements Parcelable { * consuming content. May be consumed by system to set account globally. */ public static final int KEYCODE_PROFILE_SWITCH = 288; - - /** + /** Key code constant: Video Application key #1. */ + public static final int KEYCODE_VIDEO_APP_1 = 289; + /** Key code constant: Video Application key #2. */ + public static final int KEYCODE_VIDEO_APP_2 = 290; + /** Key code constant: Video Application key #3. */ + public static final int KEYCODE_VIDEO_APP_3 = 291; + /** Key code constant: Video Application key #4. */ + public static final int KEYCODE_VIDEO_APP_4 = 292; + /** Key code constant: Video Application key #5. */ + public static final int KEYCODE_VIDEO_APP_5 = 293; + /** Key code constant: Video Application key #6. */ + public static final int KEYCODE_VIDEO_APP_6 = 294; + /** Key code constant: Video Application key #7. */ + public static final int KEYCODE_VIDEO_APP_7 = 295; + /** Key code constant: Video Application key #8. */ + public static final int KEYCODE_VIDEO_APP_8 = 296; + /** Key code constant: Featured Application key #1. */ + public static final int KEYCODE_FEATURED_APP_1 = 297; + /** Key code constant: Featured Application key #2. */ + public static final int KEYCODE_FEATURED_APP_2 = 298; + /** Key code constant: Featured Application key #3. */ + public static final int KEYCODE_FEATURED_APP_3 = 299; + /** Key code constant: Featured Application key #4. */ + public static final int KEYCODE_FEATURED_APP_4 = 300; + /** Key code constant: Demo Application key #1. */ + public static final int KEYCODE_DEMO_APP_1 = 301; + /** Key code constant: Demo Application key #2. */ + public static final int KEYCODE_DEMO_APP_2 = 302; + /** Key code constant: Demo Application key #3. */ + public static final int KEYCODE_DEMO_APP_3 = 303; + /** Key code constant: Demo Application key #4. */ + public static final int KEYCODE_DEMO_APP_4 = 304; + + /** * Integer value of the last KEYCODE. Increases as new keycodes are added to KeyEvent. * @hide */ @TestApi - public static final int LAST_KEYCODE = KEYCODE_PROFILE_SWITCH; + public static final int LAST_KEYCODE = KEYCODE_DEMO_APP_4; // NOTE: If you add a new keycode here you must also add it to: // isSystem() diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 6b5cc97d875f..4879206d6190 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -57,12 +57,15 @@ import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT; import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; +import static android.view.WindowLayout.UNSPECIFIED_LENGTH; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; +import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; +import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED; @@ -72,6 +75,7 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_V import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; @@ -90,6 +94,7 @@ import android.annotation.UiContext; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.ResourcesManager; +import android.app.WindowConfiguration; import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.content.ClipDescription; @@ -515,6 +520,8 @@ public final class ViewRootImpl implements ViewParent, private final WindowLayout mWindowLayout = new WindowLayout(); + private ViewRootImpl mParentViewRoot; + // This is used to reduce the race between window focus changes being dispatched from // the window manager and input events coming through the input system. @GuardedBy("this") @@ -1053,6 +1060,7 @@ public final class ViewRootImpl implements ViewParent, if (panelParentView != null) { mAttachInfo.mPanelParentWindowToken = panelParentView.getApplicationWindowToken(); + mParentViewRoot = panelParentView.getViewRootImpl(); } mAdded = true; int res; /* = WindowManagerImpl.ADD_OKAY; */ @@ -1113,10 +1121,13 @@ public final class ViewRootImpl implements ViewParent, final InsetsState state = mInsetsController.getState(); final Rect displayCutoutSafe = mTempRect; state.getDisplayCutoutSafe(displayCutoutSafe); + final WindowConfiguration winConfig = getConfiguration().windowConfiguration; mWindowLayout.computeWindowFrames(mWindowAttributes, state, - displayCutoutSafe, getConfiguration().windowConfiguration.getBounds(), + displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(), + UNSPECIFIED_LENGTH, UNSPECIFIED_LENGTH, mInsetsController.getRequestedVisibilities(), - null /* attachedWindowFrame */, mTmpFrames.frame, mTempRect2); + getAttachedWindowFrame(), 1f /* compactScale */, + mTmpFrames.displayFrame, mTempRect2, mTmpFrames.frame); setFrame(mTmpFrames.frame); if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow); if (res < WindowManagerGlobal.ADD_OKAY) { @@ -1227,6 +1238,14 @@ public final class ViewRootImpl implements ViewParent, } } + private Rect getAttachedWindowFrame() { + final int type = mWindowAttributes.type; + final boolean layoutAttached = (mParentViewRoot != null + && type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW + && type != TYPE_APPLICATION_ATTACHED_DIALOG); + return layoutAttached ? mParentViewRoot.mWinFrame : null; + } + /** * Register any kind of listeners if setView was success. */ diff --git a/core/java/android/view/WindowLayout.java b/core/java/android/view/WindowLayout.java index cdc1977eaad6..7dfc95ef0302 100644 --- a/core/java/android/view/WindowLayout.java +++ b/core/java/android/view/WindowLayout.java @@ -19,29 +19,44 @@ package android.view; import static android.view.InsetsState.ITYPE_IME; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_STATUS_BAR; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; +import static android.view.WindowManager.LayoutParams.FLAG_SCALED; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; +import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; +import android.app.WindowConfiguration; +import android.app.WindowConfiguration.WindowingMode; import android.graphics.Insets; import android.graphics.Rect; +import android.util.Log; /** * Computes window frames. * @hide */ public class WindowLayout { + private static final String TAG = WindowLayout.class.getSimpleName(); + private static final boolean DEBUG = false; + + public static final int UNSPECIFIED_LENGTH = -1; + private final Rect mTempDisplayCutoutSafeExceptMaybeBarsRect = new Rect(); private final Rect mTempRect = new Rect(); public boolean computeWindowFrames(WindowManager.LayoutParams attrs, InsetsState state, - Rect displayCutoutSafe, Rect windowBounds, InsetsVisibilities requestedVisibilities, - Rect attachedWindowFrame, Rect outDisplayFrame, Rect outParentFrame) { + Rect displayCutoutSafe, Rect windowBounds, @WindowingMode int windowingMode, + int requestedWidth, int requestedHeight, InsetsVisibilities requestedVisibilities, + Rect attachedWindowFrame, float compatScale, Rect outDisplayFrame, Rect outParentFrame, + Rect outFrame) { final int type = attrs.type; final int fl = attrs.flags; final int pfl = attrs.privateFlags; @@ -72,18 +87,14 @@ public class WindowLayout { } // Compute bounds restricted by display cutout + final int cutoutMode = attrs.layoutInDisplayCutoutMode; final DisplayCutout cutout = state.getDisplayCutout(); - if (cutout.isEmpty()) { - return false; - } - boolean clippedByDisplayCutout = false; final Rect displayCutoutSafeExceptMaybeBars = mTempDisplayCutoutSafeExceptMaybeBarsRect; displayCutoutSafeExceptMaybeBars.set(displayCutoutSafe); - - // Ensure that windows with a non-ALWAYS display cutout mode are laid out in - // the cutout safe zone. - final int cutoutMode = attrs.layoutInDisplayCutoutMode; - if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) { + boolean clippedByDisplayCutout = false; + if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS && !cutout.isEmpty()) { + // Ensure that windows with a non-ALWAYS display cutout mode are laid out in + // the cutout safe zone. final Rect displayFrame = state.getDisplayFrame(); final InsetsSource statusBarSource = state.peekSource(ITYPE_STATUS_BAR); if (statusBarSource != null && displayCutoutSafe.top > displayFrame.top) { @@ -147,6 +158,118 @@ public class WindowLayout { } outDisplayFrame.intersectUnchecked(displayCutoutSafeExceptMaybeBars); } + + final boolean noLimits = (attrs.flags & FLAG_LAYOUT_NO_LIMITS) != 0; + final boolean inMultiWindowMode = WindowConfiguration.inMultiWindowMode(windowingMode); + + // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it. + // Also, we don't allow windows in multi-window mode to extend out of the screen. + if (noLimits && type != TYPE_SYSTEM_ERROR && !inMultiWindowMode) { + outDisplayFrame.left = outDisplayFrame.top = -10000; + outDisplayFrame.right = outDisplayFrame.bottom = 10000; + } + + final boolean hasCompatScale = compatScale != 1f; + final int pw = outParentFrame.width(); + final int ph = outParentFrame.height(); + int rw = requestedWidth; + int rh = requestedHeight; + float x, y; + int w, h; + + // If the view hierarchy hasn't been measured, the requested width and height would be + // UNSPECIFIED_LENGTH. This can happen in the first layout of a window or in the simulated + // layout. + if (rw == UNSPECIFIED_LENGTH) { + rw = attrs.width >= 0 ? attrs.width : pw; + } + if (rh == UNSPECIFIED_LENGTH) { + rh = attrs.height >= 0 ? attrs.height : ph; + } + + if ((attrs.flags & FLAG_SCALED) != 0) { + if (attrs.width < 0) { + w = pw; + } else if (hasCompatScale) { + w = (int) (attrs.width * compatScale + .5f); + } else { + w = attrs.width; + } + if (attrs.height < 0) { + h = ph; + } else if (hasCompatScale) { + h = (int) (attrs.height * compatScale + .5f); + } else { + h = attrs.height; + } + } else { + if (attrs.width == MATCH_PARENT) { + w = pw; + } else if (hasCompatScale) { + w = (int) (rw * compatScale + .5f); + } else { + w = rw; + } + if (attrs.height == MATCH_PARENT) { + h = ph; + } else if (hasCompatScale) { + h = (int) (rh * compatScale + .5f); + } else { + h = rh; + } + } + + if (hasCompatScale) { + x = attrs.x * compatScale; + y = attrs.y * compatScale; + } else { + x = attrs.x; + y = attrs.y; + } + + if (inMultiWindowMode + && (attrs.privateFlags & PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME) == 0) { + // Make sure window fits in parent frame since it is in a non-fullscreen task as + // required by {@link Gravity#apply} call. + w = Math.min(w, pw); + h = Math.min(h, ph); + } + + // We need to fit it to the display if either + // a) The window is in a fullscreen container, or we don't have a task (we assume fullscreen + // for the taskless windows) + // b) If it's a secondary app window, we also need to fit it to the display unless + // FLAG_LAYOUT_NO_LIMITS is set. This is so we place Popups, dialogs, and similar windows on + // screen, but SurfaceViews want to be always at a specific location so we don't fit it to + // the display. + final boolean fitToDisplay = !inMultiWindowMode + || ((attrs.type != TYPE_BASE_APPLICATION) && !noLimits); + + // Set mFrame + Gravity.apply(attrs.gravity, w, h, outParentFrame, + (int) (x + attrs.horizontalMargin * pw), + (int) (y + attrs.verticalMargin * ph), outFrame); + // Now make sure the window fits in the overall display frame. + if (fitToDisplay) { + Gravity.applyDisplay(attrs.gravity, outDisplayFrame, outFrame); + } + + if (DEBUG) Log.d(TAG, "computeWindowFrames " + attrs.getTitle() + + " outFrame=" + outFrame.toShortString() + + " outParentFrame=" + outParentFrame.toShortString() + + " outDisplayFrame=" + outDisplayFrame.toShortString() + + " attachedWindowFrame=" + (attachedWindowFrame != null + ? attachedWindowFrame.toShortString() + : "null") + + " requestedWidth=" + requestedWidth + + " requestedHeight=" + requestedHeight + + " compatScale=" + compatScale + + " windowingMode=" + WindowConfiguration.windowingModeToString(windowingMode) + + " displayCutoutSafe=" + displayCutoutSafe + + " attrs=" + attrs + + " state=" + state + + " requestedVisibilities=" + requestedVisibilities); + return clippedByDisplayCutout; } } diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index 5ad0055dae78..3248cf513c84 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -529,7 +529,7 @@ message ConfigurationContainerProto { message WindowFramesProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; - optional .android.graphics.RectProto containing_frame = 1; + optional .android.graphics.RectProto containing_frame = 1 [deprecated=true]; optional .android.graphics.RectProto content_frame = 2 [deprecated=true]; optional .android.graphics.RectProto decor_frame = 3 [deprecated=true]; optional .android.graphics.RectProto display_frame = 4; diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 765495aea546..06333e19ce5e 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -1984,6 +1984,22 @@ <enum name="KEYCODE_THUMBS_UP" value="286" /> <enum name="KEYCODE_THUMBS_DOWN" value="287" /> <enum name="KEYCODE_PROFILE_SWITCH" value="288" /> + <enum name="KEYCODE_VIDEO_APP_1" value="289" /> + <enum name="KEYCODE_VIDEO_APP_2" value="290" /> + <enum name="KEYCODE_VIDEO_APP_3" value="291" /> + <enum name="KEYCODE_VIDEO_APP_4" value="292" /> + <enum name="KEYCODE_VIDEO_APP_5" value="293" /> + <enum name="KEYCODE_VIDEO_APP_6" value="294" /> + <enum name="KEYCODE_VIDEO_APP_7" value="295" /> + <enum name="KEYCODE_VIDEO_APP_8" value="296" /> + <enum name="KEYCODE_FEATURED_APP_1" value="297" /> + <enum name="KEYCODE_FEATURED_APP_2" value="298" /> + <enum name="KEYCODE_FEATURED_APP_3" value="299" /> + <enum name="KEYCODE_FEATURED_APP_4" value="300" /> + <enum name="KEYCODE_DEMO_APP_1" value="301" /> + <enum name="KEYCODE_DEMO_APP_2" value="302" /> + <enum name="KEYCODE_DEMO_APP_3" value="303" /> + <enum name="KEYCODE_DEMO_APP_4" value="304" /> </attr> <!-- ***************************************************************** --> diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml index a65de9128be9..205c517d2b84 100644 --- a/core/res/res/xml/sms_short_codes.xml +++ b/core/res/res/xml/sms_short_codes.xml @@ -105,6 +105,9 @@ http://www.tja.ee/public/documents/Elektrooniline_side/Oigusaktid/ENG/Estonian_Numbering_Plan_annex_06_09_2010.mht --> <shortcode country="ee" pattern="1\\d{2,4}" premium="90\\d{5}|15330|1701[0-3]" free="116\\d{3}|95034" /> + <!-- Egypt: 4 digits, known codes listed --> + <shortcode country="eg" pattern="\\d{4}" free="1499" /> + <!-- Spain: 5-6 digits: 25xxx, 27xxx, 280xx, 35xxx, 37xxx, 795xxx, 797xxx, 995xxx, 997xxx, plus EU. http://www.legallink.es/?q=en/content/which-current-regulatory-status-premium-rate-services-spain --> <shortcode country="es" premium="[23][57]\\d{3}|280\\d{2}|[79]9[57]\\d{3}" free="116\\d{3}|22791|222145|22189" /> @@ -196,7 +199,7 @@ <shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223|1662" /> <!-- Nigeria --> - <shortcode country="ng" pattern="\\d{1,5}" free="2441|55019" /> + <shortcode country="ng" pattern="\\d{1,5}" free="2441|55020" /> <!-- Norway: 4-5 digits (not confirmed), known premium codes listed --> <shortcode country="no" pattern="\\d{4,5}" premium="2201|222[67]" free="2171" /> 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 5b3ce2dbaeb9..b1b0382b401c 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 @@ -565,11 +565,11 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange mDismissingDimValue = 0; int totalDismissingDistance = 0; - if (position <= mDividerSnapAlgorithm.getFirstSplitTarget().position) { + if (position < mDividerSnapAlgorithm.getFirstSplitTarget().position) { mDismissingSide = isLandscape ? DOCKED_LEFT : DOCKED_TOP; totalDismissingDistance = mDividerSnapAlgorithm.getDismissStartTarget().position - mDividerSnapAlgorithm.getFirstSplitTarget().position; - } else if (position >= mDividerSnapAlgorithm.getLastSplitTarget().position) { + } else if (position > mDividerSnapAlgorithm.getLastSplitTarget().position) { mDismissingSide = isLandscape ? DOCKED_RIGHT : DOCKED_BOTTOM; totalDismissingDistance = mDividerSnapAlgorithm.getLastSplitTarget().position - mDividerSnapAlgorithm.getDismissEndTarget().position; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java index 291cbb3676dc..b6e5804a64dd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java @@ -1292,13 +1292,17 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, } Rect baseBounds = direction == TRANSITION_DIRECTION_SNAP_AFTER_RESIZE ? mPipBoundsState.getBounds() : currentBounds; + final boolean existingAnimatorRunning = mPipAnimationController.getCurrentAnimator() != null + && mPipAnimationController.getCurrentAnimator().isRunning(); final PipAnimationController.PipTransitionAnimator<?> animator = mPipAnimationController .getAnimator(mTaskInfo, mLeash, baseBounds, currentBounds, destinationBounds, sourceHintRect, direction, startingAngle, rotationDelta); animator.setTransitionDirection(direction) - .setPipAnimationCallback(mPipAnimationCallback) .setPipTransactionHandler(mPipTransactionHandler) .setDuration(durationMs); + if (!existingAnimatorRunning) { + animator.setPipAnimationCallback(mPipAnimationCallback); + } if (isInPipDirection(direction)) { // Similar to auto-enter-pip transition, we use content overlay when there is no // source rect hint to enter PiP use bounds animation. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java index 328f3ed73f2e..b31e6e0750ce 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java @@ -116,6 +116,12 @@ public class PipTransition extends PipTransitionController { if (mExitTransition == transition || info.getType() == TRANSIT_EXIT_PIP) { mExitTransition = null; if (info.getChanges().size() == 1) { + if (mFinishCallback != null) { + mFinishCallback.onTransitionFinished(null, null); + mFinishCallback = null; + throw new RuntimeException("Previous callback not called, aborting exit PIP."); + } + final TransitionInfo.Change change = info.getChanges().get(0); mFinishCallback = finishCallback; startTransaction.apply(); @@ -129,6 +135,12 @@ public class PipTransition extends PipTransitionController { } if (info.getType() == TRANSIT_REMOVE_PIP) { + if (mFinishCallback != null) { + mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */); + mFinishCallback = null; + throw new RuntimeException("Previous callback not called, aborting remove PIP."); + } + startTransaction.apply(); finishTransaction.setWindowCrop(info.getChanges().get(0).getLeash(), mPipBoundsState.getDisplayBounds()); @@ -159,6 +171,12 @@ public class PipTransition extends PipTransitionController { return false; } + if (mFinishCallback != null) { + mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */); + mFinishCallback = null; + throw new RuntimeException("Previous callback not called, aborting entering PIP."); + } + // Show the wallpaper if there is a wallpaper change. if (wallpaper != null) { startTransaction.show(wallpaper.getLeash()); @@ -231,7 +249,7 @@ public class PipTransition extends PipTransitionController { if (tx != null) { wct.setBoundsChangeTransaction(taskInfo.token, tx); } - mFinishCallback.onTransitionFinished(wct, null /* wctCallback */); + mFinishCallback.onTransitionFinished(wct, null /* callback */); mFinishCallback = null; } finishResizeForMenu(destinationBounds); @@ -240,7 +258,7 @@ public class PipTransition extends PipTransitionController { @Override public void forceFinishTransition() { if (mFinishCallback == null) return; - mFinishCallback.onTransitionFinished(null /* wct */, null /* wctCallback */); + mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */); mFinishCallback = null; } @@ -286,7 +304,6 @@ public class PipTransition extends PipTransitionController { mPipBoundsState.setBounds(destinationBounds); onFinishResize(taskInfo, destinationBounds, TRANSITION_DIRECTION_TO_PIP, null /* tx */); sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP); - mFinishCallback = null; mPipTransitionState.setInSwipePipToHomeTransition(false); return true; } diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java index 49477b94cbe0..374cc7592faf 100644 --- a/media/java/android/media/MediaCodecInfo.java +++ b/media/java/android/media/MediaCodecInfo.java @@ -182,10 +182,15 @@ public final class MediaCodecInfo { public String mName; public int mValue; public boolean mDefault; + public boolean mInternal; public Feature(String name, int value, boolean def) { + this(name, value, def, false /* internal */); + } + public Feature(String name, int value, boolean def, boolean internal) { mName = name; mValue = value; mDefault = def; + mInternal = internal; } } @@ -579,6 +584,11 @@ public final class MediaCodecInfo { public static final String FEATURE_LowLatency = "low-latency"; /** + * Do not include in REGULAR_CODECS list in MediaCodecList. + */ + private static final String FEATURE_SpecialCodec = "special-codec"; + + /** * <b>video encoder only</b>: codec supports quantization parameter bounds. * @see MediaFormat#KEY_VIDEO_QP_MAX * @see MediaFormat#KEY_VIDEO_QP_MIN @@ -616,6 +626,8 @@ public final class MediaCodecInfo { new Feature(FEATURE_MultipleFrames, (1 << 5), false), new Feature(FEATURE_DynamicTimestamp, (1 << 6), false), new Feature(FEATURE_LowLatency, (1 << 7), true), + // feature to exclude codec from REGULAR codec list + new Feature(FEATURE_SpecialCodec, (1 << 30), false, true), }; private static final Feature[] encoderFeatures = { @@ -623,6 +635,8 @@ public final class MediaCodecInfo { new Feature(FEATURE_MultipleFrames, (1 << 1), false), new Feature(FEATURE_DynamicTimestamp, (1 << 2), false), new Feature(FEATURE_QpBounds, (1 << 3), false), + // feature to exclude codec from REGULAR codec list + new Feature(FEATURE_SpecialCodec, (1 << 30), false, true), }; /** @hide */ @@ -630,7 +644,9 @@ public final class MediaCodecInfo { Feature[] features = getValidFeatures(); String[] res = new String[features.length]; for (int i = 0; i < res.length; i++) { - res[i] = features[i].mName; + if (!features[i].mInternal) { + res[i] = features[i].mName; + } } return res; } @@ -778,6 +794,10 @@ public final class MediaCodecInfo { // check feature support for (Feature feat: getValidFeatures()) { + if (feat.mInternal) { + continue; + } + Integer yesNo = (Integer)map.get(MediaFormat.KEY_FEATURE_ + feat.mName); if (yesNo == null) { continue; @@ -1091,7 +1111,9 @@ public final class MediaCodecInfo { mFlagsRequired |= feat.mValue; } mFlagsSupported |= feat.mValue; - mDefaultFormat.setInteger(key, 1); + if (!feat.mInternal) { + mDefaultFormat.setInteger(key, 1); + } // TODO restrict features by mFlagsVerified once all codecs reliably verify them } } diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index 08a648a83daa..4891d74f868f 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -754,7 +754,7 @@ public final class MediaFormat { * <p>This key is only used during decoding. */ public static final String KEY_MAX_OUTPUT_CHANNEL_COUNT = - "max-output-channel_count"; + "max-output-channel-count"; /** * A key describing the number of frames to trim from the start of the decoded audio stream. diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index 9dc4949799cd..405f9eedab14 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -751,8 +751,13 @@ public class Tuner implements AutoCloseable { */ @Result public int tune(@NonNull FrontendSettings settings) { - Log.d(TAG, "Tune to " + settings.getFrequency()); - mFrontendType = settings.getType(); + final int type = settings.getType(); + if (mFrontendHandle != null && type != mFrontendType) { + Log.e(TAG, "Frontend was opened with type " + mFrontendType + ", new type is " + type); + return RESULT_INVALID_STATE; + } + Log.d(TAG, "Tune to " + settings.getFrequencyLong()); + mFrontendType = type; if (mFrontendType == FrontendSettings.TYPE_DTMB) { if (!TunerVersionChecker.checkHigherOrEqualVersionTo( TunerVersionChecker.TUNER_VERSION_1_1, "Tuner with DTMB Frontend")) { diff --git a/packages/PackageInstaller/OWNERS b/packages/PackageInstaller/OWNERS index c6331133367a..27368705c6b0 100644 --- a/packages/PackageInstaller/OWNERS +++ b/packages/PackageInstaller/OWNERS @@ -1,7 +1,5 @@ svetoslavganov@google.com -toddke@google.com -patb@google.com -suprabh@google.com +include /PACKAGE_MANAGER_OWNERS # For automotive related changes rogerxue@google.com diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/OWNERS b/packages/SettingsLib/src/com/android/settingslib/inputmethod/OWNERS index a0e28baee3f6..5b2e1e3b50d3 100644 --- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/OWNERS +++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/OWNERS @@ -1,5 +1,6 @@ # Default reviewers for this and subdirectories. takaoka@google.com yukawa@google.com +wilsonwu@google.com # Emergency approvers in case the above are not available
\ No newline at end of file diff --git a/packages/SettingsProvider/OWNERS b/packages/SettingsProvider/OWNERS index 6c61d4b91d36..5ade9716c8cb 100644 --- a/packages/SettingsProvider/OWNERS +++ b/packages/SettingsProvider/OWNERS @@ -2,6 +2,4 @@ hackbod@android.com hackbod@google.com narayan@google.com svetoslavganov@google.com -schfan@google.com -toddke@google.com -patb@google.com +include /PACKAGE_MANAGER_OWNERS diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags index 61147281da6f..a110413700b2 100644 --- a/packages/SystemUI/proguard.flags +++ b/packages/SystemUI/proguard.flags @@ -1,20 +1,3 @@ --keep class com.android.systemui.navigationbar.buttons.KeyButtonView { - public float getDrawingAlpha(); - public void setDrawingAlpha(float); -} - --keep class com.android.systemui.navigationbar.buttons.KeyButtonRipple { - public float getGlowAlpha(); - public float getGlowScale(); - public void setGlowAlpha(float); - public void setGlowScale(float); -} - --keep class com.android.systemui.settings.brightness.BrightnessSliderView { - public float getSliderScaleY(); - public void setSliderScaleY(float); -} - -keep class com.android.systemui.recents.OverviewProxyRecentsImpl -keep class com.android.systemui.statusbar.car.CarStatusBar -keep class com.android.systemui.statusbar.phone.StatusBar diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java index cac90ea60e97..8c7ede26e2e6 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java @@ -49,7 +49,7 @@ import dagger.Lazy; public class KeyguardDisplayManager { protected static final String TAG = "KeyguardDisplayManager"; - private static boolean DEBUG = KeyguardConstants.DEBUG; + private static final boolean DEBUG = KeyguardConstants.DEBUG; private MediaRouter mMediaRouter = null; private final DisplayManager mDisplayService; diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt index b7398d86c16e..e2a2d07bdf35 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt @@ -22,6 +22,7 @@ import android.graphics.PorterDuffColorFilter import android.graphics.Rect import android.hardware.biometrics.BiometricOverlayConstants import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD +import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS import android.hardware.display.DisplayManager import android.hardware.fingerprint.FingerprintManager import android.hardware.fingerprint.FingerprintSensorPropertiesInternal @@ -181,6 +182,7 @@ class SidefpsController @Inject constructor( @BiometricOverlayConstants.ShowReason private fun Int.isReasonToShow(): Boolean = when (this) { REASON_AUTH_KEYGUARD -> false + REASON_AUTH_SETTINGS -> false else -> true } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java index e3e2367aeef8..2ea706c16b7e 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java @@ -34,6 +34,8 @@ import android.view.View; import android.view.ViewConfiguration; import android.view.animation.Interpolator; +import androidx.annotation.Keep; + import com.android.systemui.R; import com.android.systemui.animation.Interpolators; @@ -184,19 +186,27 @@ public class KeyButtonRipple extends Drawable { } } + /** Gets the glow alpha, used by {@link android.animation.ObjectAnimator} via reflection. */ + @Keep public float getGlowAlpha() { return mGlowAlpha; } + /** Sets the glow alpha, used by {@link android.animation.ObjectAnimator} via reflection. */ + @Keep public void setGlowAlpha(float x) { mGlowAlpha = x; invalidateSelf(); } + /** Gets the glow scale, used by {@link android.animation.ObjectAnimator} via reflection. */ + @Keep public float getGlowScale() { return mGlowScale; } + /** Sets the glow scale, used by {@link android.animation.ObjectAnimator} via reflection. */ + @Keep public void setGlowScale(float x) { mGlowScale = x; invalidateSelf(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt index bc21b2d0fba7..80ec0adc21a9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt @@ -112,20 +112,9 @@ class DeviceControlsTile @Inject constructor( } mUiHandler.post { - if (keyguardStateController.isUnlocked) { - mActivityStarter.startActivity( - intent, true /* dismissShade */, animationController) - } else { - if (state.state == Tile.STATE_ACTIVE) { - mHost.collapsePanels() - // With an active tile, don't use ActivityStarter so that the activity is - // started without prompting keyguard unlock. - mContext.startActivity(intent) - } else { - mActivityStarter.postStartActivityDismissingKeyguard( - intent, 0 /* delay */, animationController) - } - } + val showOverLockscreenWhenLocked = state.state == Tile.STATE_ACTIVE + mActivityStarter.startActivity( + intent, true /* dismissShade */, animationController, showOverLockscreenWhenLocked) } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java index 15b78e7cb08a..58e899285e3b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java @@ -331,7 +331,7 @@ public class InternetDialog extends SystemUIDialog implements showProgressBar(); final boolean isDeviceLocked = mInternetDialogController.isDeviceLocked(); final boolean isWifiEnabled = mWifiManager.isWifiEnabled(); - final boolean isWifiScanEnabled = mWifiManager.isScanAlwaysAvailable(); + final boolean isWifiScanEnabled = mInternetDialogController.isWifiScanEnabled(); updateWifiToggle(isWifiEnabled, isDeviceLocked); updateConnectedWifi(isWifiEnabled, isDeviceLocked); updateWifiScanNotify(isWifiEnabled, isWifiScanEnabled, isDeviceLocked); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java index 1ade5ce39c27..40590a76536e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java @@ -78,6 +78,7 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.statusbar.connectivity.NetworkController; import com.android.systemui.statusbar.connectivity.NetworkController.AccessPointController; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.statusbar.policy.LocationController; import com.android.systemui.toast.SystemUIToast; import com.android.systemui.toast.ToastFactory; import com.android.systemui.util.CarrierConfigTracker; @@ -150,6 +151,7 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, private WindowManager mWindowManager; private ToastFactory mToastFactory; private SignalDrawable mSignalDrawable; + private LocationController mLocationController; @VisibleForTesting static final float TOAST_PARAMS_HORIZONTAL_WEIGHT = 1.0f; @@ -199,7 +201,8 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, GlobalSettings globalSettings, KeyguardStateController keyguardStateController, WindowManager windowManager, ToastFactory toastFactory, @Background Handler workerHandler, - CarrierConfigTracker carrierConfigTracker) { + CarrierConfigTracker carrierConfigTracker, + LocationController locationController) { if (DEBUG) { Log.d(TAG, "Init InternetDialogController"); } @@ -227,6 +230,7 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, mWindowManager = windowManager; mToastFactory = toastFactory; mSignalDrawable = new SignalDrawable(mContext); + mLocationController = locationController; } void onStart(@NonNull InternetDialogCallback callback, boolean canConfigWifi) { @@ -788,6 +792,14 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, return false; } + @WorkerThread + boolean isWifiScanEnabled() { + if (!mLocationController.isLocationEnabled()) { + return false; + } + return mWifiManager.isScanAlwaysAvailable(); + } + static class WifiEntryConnectCallback implements WifiEntry.ConnectCallback { final ActivityStarter mActivityStarter; final WifiEntry mWifiEntry; diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java index 15aa2b730adf..a4e1537bd831 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java +++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java @@ -27,6 +27,7 @@ import android.view.View; import android.widget.FrameLayout; import android.widget.SeekBar.OnSeekBarChangeListener; +import androidx.annotation.Keep; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -183,6 +184,7 @@ public class BrightnessSliderView extends FrameLayout { * * Used in {@link com.android.systemui.qs.QSAnimator}. */ + @Keep public void setSliderScaleY(float scale) { if (scale != mScale) { mScale = scale; @@ -199,6 +201,7 @@ public class BrightnessSliderView extends FrameLayout { } } + @Keep public float getSliderScaleY() { return mScale; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index c639eecf037c..e26f75f7ce40 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -1078,10 +1078,14 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK) .putExtra(ControlsUiController.EXTRA_ANIMATE, true); + ActivityLaunchAnimator.Controller controller = + v != null ? ActivityLaunchAnimator.Controller.fromView(v, null /* cujType */) + : null; if (mControlsComponent.getVisibility() == AVAILABLE) { - mContext.startActivity(intent); + mActivityStarter.startActivity(intent, true /* dismissShade */, controller, + true /* showOverLockscreenWhenLocked */); } else { - mActivityStarter.postStartActivityDismissingKeyguard(intent, 0 /* delay */); + mActivityStarter.postStartActivityDismissingKeyguard(intent, 0 /* delay */, controller); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt index 16d7f983d0f3..6ae8331dfde5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt @@ -156,18 +156,21 @@ class StatusBarContentInsetsProvider @Inject constructor( val isRtl = rotatedResources.configuration.layoutDirection == LAYOUT_DIRECTION_RTL val roundedCornerPadding = rotatedResources .getDimensionPixelSize(R.dimen.rounded_corner_content_padding) - val minDotWidth = if (isPrivacyDotEnabled) + val minDotPadding = if (isPrivacyDotEnabled) rotatedResources.getDimensionPixelSize(R.dimen.ongoing_appops_dot_min_padding) else 0 + val dotWidth = if (isPrivacyDotEnabled) + rotatedResources.getDimensionPixelSize(R.dimen.ongoing_appops_dot_diameter) + else 0 val minLeft: Int val minRight: Int if (isRtl) { - minLeft = max(minDotWidth, roundedCornerPadding) + minLeft = max(minDotPadding, roundedCornerPadding) minRight = roundedCornerPadding } else { minLeft = roundedCornerPadding - minRight = max(minDotWidth, roundedCornerPadding) + minRight = max(minDotPadding, roundedCornerPadding) } return calculateInsetsForRotationWithRotatedResources( @@ -177,7 +180,9 @@ class StatusBarContentInsetsProvider @Inject constructor( context.resources.configuration.windowConfiguration.maxBounds, SystemBarUtils.getStatusBarHeight(context), minLeft, - minRight) + minRight, + isRtl, + dotWidth) } fun getStatusBarPaddingTop(@Rotation rotation: Int? = null): Int { @@ -246,10 +251,13 @@ fun getPrivacyChipBoundingRectForInsets( * * @param currentRotation current device rotation * @param targetRotation rotation for which to calculate the status bar content rect - * @param displayCutout [DisplayCutout] for the curren display. possibly null + * @param displayCutout [DisplayCutout] for the current display. possibly null * @param windowMetrics [WindowMetrics] for the current window * @param statusBarHeight height of the status bar for the target rotation - * @param roundedCornerPadding from rounded_corner_content_padding + * @param minLeft the minimum padding to enforce on the left + * @param minRight the minimum padding to enforce on the right + * @param isRtl current layout direction is Right-To-Left or not + * @param dotWidth privacy dot image width (0 if privacy dot is disabled) * * @see [RotationUtils#getResourcesForRotation] */ @@ -260,7 +268,9 @@ fun calculateInsetsForRotationWithRotatedResources( maxBounds: Rect, statusBarHeight: Int, minLeft: Int, - minRight: Int + minRight: Int, + isRtl: Boolean, + dotWidth: Int ): Rect { /* TODO: Check if this is ever used for devices with no rounded corners @@ -279,6 +289,8 @@ fun calculateInsetsForRotationWithRotatedResources( maxBounds.height(), minLeft, minRight, + isRtl, + dotWidth, targetRotation, currentRotation) @@ -296,6 +308,8 @@ fun calculateInsetsForRotationWithRotatedResources( * @param cHeight display height in our current rotation * @param minLeft the minimum padding to enforce on the left * @param minRight the minimum padding to enforce on the right + * @param isRtl current layout direction is Right-To-Left or not + * @param dotWidth privacy dot image width (0 if privacy dot is disabled) * @param targetRotation the rotation for which to calculate margins * @param currentRotation the rotation from which the display cutout was generated * @@ -311,6 +325,8 @@ private fun getStatusBarLeftRight( cHeight: Int, minLeft: Int, minRight: Int, + isRtl: Boolean, + dotWidth: Int, @Rotation targetRotation: Int, @Rotation currentRotation: Int ): Rect { @@ -345,13 +361,16 @@ private fun getStatusBarLeftRight( } if (cutoutRect.touchesLeftEdge(relativeRotation, cWidth, cHeight)) { - - val l = max(minLeft, cutoutRect.logicalWidth(relativeRotation)) - leftMargin = max(l, leftMargin) + var logicalWidth = cutoutRect.logicalWidth(relativeRotation) + if (isRtl) logicalWidth += dotWidth + leftMargin = max(logicalWidth, leftMargin) } else if (cutoutRect.touchesRightEdge(relativeRotation, cWidth, cHeight)) { - val logicalWidth = cutoutRect.logicalWidth(relativeRotation) - rightMargin = max(minRight, logicalWidth) + var logicalWidth = cutoutRect.logicalWidth(relativeRotation) + if (!isRtl) logicalWidth += dotWidth + rightMargin = max(rightMargin, logicalWidth) } + // TODO(b/203626889): Fix the scenario when config_mainBuiltInDisplayCutoutRectApproximation + // is very close to but not directly touch edges. } return Rect(leftMargin, 0, logicalDisplayWidth - rightMargin, sbHeight) diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt index 5fee7fbf8705..ca7d506dcc78 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt @@ -18,6 +18,7 @@ package com.android.systemui.biometrics import android.graphics.Rect import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD +import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS import android.hardware.biometrics.BiometricOverlayConstants.REASON_UNKNOWN import android.hardware.biometrics.SensorProperties import android.hardware.display.DisplayManager @@ -182,7 +183,16 @@ class SidefpsControllerTest : SysuiTestCase() { @Test fun testIgnoredForKeyguard() { - overlayController.show(SENSOR_ID, REASON_AUTH_KEYGUARD) + testIgnoredFor(REASON_AUTH_KEYGUARD) + } + + @Test + fun testIgnoredForSettings() { + testIgnoredFor(REASON_AUTH_SETTINGS) + } + + private fun testIgnoredFor(reason: Int) { + overlayController.show(SENSOR_ID, reason) executor.runAllReady() verify(windowManager, never()).addView(any(), any()) diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt index 94af10a485fd..98c7274aeba6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt @@ -52,13 +52,11 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor -import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.`when` import org.mockito.Mockito.doNothing -import org.mockito.Mockito.never import org.mockito.Mockito.nullable import org.mockito.Mockito.spy import org.mockito.Mockito.verify @@ -272,28 +270,7 @@ class DeviceControlsTileTest : SysuiTestCase() { } @Test - fun handleClick_availableAndLocked_activityStarted() { - verify(controlsListingController).observe( - any(LifecycleOwner::class.java), - capture(listingCallbackCaptor) - ) - `when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE) - `when`(keyguardStateController.isUnlocked).thenReturn(false) - - listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo)) - testableLooper.processAllMessages() - - tile.click(null /* view */) - testableLooper.processAllMessages() - - // The activity should be started right away and not require a keyguard dismiss. - verifyZeroInteractions(activityStarter) - verify(spiedContext).startActivity(intentCaptor.capture()) - assertThat(intentCaptor.value.component?.className).isEqualTo(CONTROLS_ACTIVITY_CLASS_NAME) - } - - @Test - fun handleClick_availableAndUnlocked_activityStarted() { + fun handleClick_available_shownOverLockscreenWhenLocked() { verify(controlsListingController).observe( any(LifecycleOwner::class.java), capture(listingCallbackCaptor) @@ -307,16 +284,16 @@ class DeviceControlsTileTest : SysuiTestCase() { tile.click(null /* view */) testableLooper.processAllMessages() - verify(activityStarter, never()).postStartActivityDismissingKeyguard(any(), anyInt()) verify(activityStarter).startActivity( intentCaptor.capture(), eq(true) /* dismissShade */, - nullable(ActivityLaunchAnimator.Controller::class.java)) + nullable(ActivityLaunchAnimator.Controller::class.java), + eq(true) /* showOverLockscreenWhenLocked */) assertThat(intentCaptor.value.component?.className).isEqualTo(CONTROLS_ACTIVITY_CLASS_NAME) } @Test - fun handleClick_availableAfterUnlockAndIsLocked_keyguardDismissRequired() { + fun handleClick_availableAfterUnlock_notShownOverLockscreenWhenLocked() { verify(controlsListingController).observe( any(LifecycleOwner::class.java), capture(listingCallbackCaptor) @@ -331,38 +308,11 @@ class DeviceControlsTileTest : SysuiTestCase() { tile.click(null /* view */) testableLooper.processAllMessages() - verify(activityStarter, never()).startActivity( - any(), - anyBoolean() /* dismissShade */, - nullable(ActivityLaunchAnimator.Controller::class.java)) - verify(activityStarter).postStartActivityDismissingKeyguard( - intentCaptor.capture(), - anyInt(), - nullable(ActivityLaunchAnimator.Controller::class.java)) - assertThat(intentCaptor.value.component?.className).isEqualTo(CONTROLS_ACTIVITY_CLASS_NAME) - } - - @Test - fun handleClick_availableAfterUnlockAndIsUnlocked_activityStarted() { - verify(controlsListingController).observe( - any(LifecycleOwner::class.java), - capture(listingCallbackCaptor) - ) - `when`(controlsComponent.getVisibility()) - .thenReturn(ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK) - `when`(keyguardStateController.isUnlocked).thenReturn(true) - - listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo)) - testableLooper.processAllMessages() - - tile.click(null /* view */) - testableLooper.processAllMessages() - - verify(activityStarter, never()).postStartActivityDismissingKeyguard(any(), anyInt()) verify(activityStarter).startActivity( intentCaptor.capture(), - eq(true) /* dismissShade */, - nullable(ActivityLaunchAnimator.Controller::class.java)) + anyBoolean() /* dismissShade */, + nullable(ActivityLaunchAnimator.Controller::class.java), + eq(false) /* showOverLockscreenWhenLocked */) assertThat(intentCaptor.value.component?.className).isEqualTo(CONTROLS_ACTIVITY_CLASS_NAME) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java index fe328395b89f..5cea7632192b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java @@ -51,6 +51,7 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.statusbar.connectivity.NetworkController; import com.android.systemui.statusbar.connectivity.NetworkController.AccessPointController; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.statusbar.policy.LocationController; import com.android.systemui.toast.SystemUIToast; import com.android.systemui.toast.ToastFactory; import com.android.systemui.util.CarrierConfigTracker; @@ -135,6 +136,8 @@ public class InternetDialogControllerTest extends SysuiTestCase { private Animator mAnimator; @Mock private CarrierConfigTracker mCarrierConfigTracker; + @Mock + private LocationController mLocationController; private TestableResources mTestableResources; private MockInternetDialogController mInternetDialogController; @@ -170,7 +173,8 @@ public class InternetDialogControllerTest extends SysuiTestCase { mSubscriptionManager, mTelephonyManager, mWifiManager, mock(ConnectivityManager.class), mHandler, mExecutor, mBroadcastDispatcher, mock(KeyguardUpdateMonitor.class), mGlobalSettings, mKeyguardStateController, - mWindowManager, mToastFactory, mWorkerHandler, mCarrierConfigTracker); + mWindowManager, mToastFactory, mWorkerHandler, mCarrierConfigTracker, + mLocationController); mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor, mInternetDialogController.mOnSubscriptionsChangedListener); mInternetDialogController.onStart(mInternetDialogCallback, true); @@ -602,6 +606,30 @@ public class InternetDialogControllerTest extends SysuiTestCase { verify(mMergedCarrierEntry).setEnabled(false); } + @Test + public void isWifiScanEnabled_locationOff_returnFalse() { + when(mLocationController.isLocationEnabled()).thenReturn(false); + when(mWifiManager.isScanAlwaysAvailable()).thenReturn(false); + + assertThat(mInternetDialogController.isWifiScanEnabled()).isFalse(); + + when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true); + + assertThat(mInternetDialogController.isWifiScanEnabled()).isFalse(); + } + + @Test + public void isWifiScanEnabled_locationOn_returnIsScanAlwaysAvailable() { + when(mLocationController.isLocationEnabled()).thenReturn(true); + when(mWifiManager.isScanAlwaysAvailable()).thenReturn(false); + + assertThat(mInternetDialogController.isWifiScanEnabled()).isFalse(); + + when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true); + + assertThat(mInternetDialogController.isWifiScanEnabled()).isTrue(); + } + private String getResourcesString(String name) { return mContext.getResources().getString(getResourcesId(name)); } @@ -625,12 +653,13 @@ public class InternetDialogControllerTest extends SysuiTestCase { KeyguardUpdateMonitor keyguardUpdateMonitor, GlobalSettings globalSettings, KeyguardStateController keyguardStateController, WindowManager windowManager, ToastFactory toastFactory, Handler workerHandler, - CarrierConfigTracker carrierConfigTracker) { + CarrierConfigTracker carrierConfigTracker, + LocationController locationController) { super(context, uiEventLogger, starter, accessPointController, subscriptionManager, telephonyManager, wifiManager, connectivityManager, handler, mainExecutor, broadcastDispatcher, keyguardUpdateMonitor, globalSettings, keyguardStateController, windowManager, toastFactory, workerHandler, - carrierConfigTracker); + carrierConfigTracker, locationController); mGlobalSettings = globalSettings; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java index 66889607482f..5e1fea512d55 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java @@ -282,7 +282,7 @@ public class InternetDialogTest extends SysuiTestCase { @Test public void updateDialog_wifiOffAndWifiScanOff_hideWifiScanNotify() { when(mWifiManager.isWifiEnabled()).thenReturn(false); - when(mWifiManager.isScanAlwaysAvailable()).thenReturn(false); + when(mInternetDialogController.isWifiScanEnabled()).thenReturn(false); mInternetDialog.updateDialog(false); @@ -292,7 +292,7 @@ public class InternetDialogTest extends SysuiTestCase { @Test public void updateDialog_wifiOffAndWifiScanOnAndDeviceLocked_hideWifiScanNotify() { when(mWifiManager.isWifiEnabled()).thenReturn(false); - when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true); + when(mInternetDialogController.isWifiScanEnabled()).thenReturn(true); when(mInternetDialogController.isDeviceLocked()).thenReturn(true); mInternetDialog.updateDialog(false); @@ -303,7 +303,7 @@ public class InternetDialogTest extends SysuiTestCase { @Test public void updateDialog_wifiOffAndWifiScanOnAndDeviceUnlocked_showWifiScanNotify() { when(mWifiManager.isWifiEnabled()).thenReturn(false); - when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true); + when(mInternetDialogController.isWifiScanEnabled()).thenReturn(true); when(mInternetDialogController.isDeviceLocked()).thenReturn(false); mInternetDialog.updateDialog(false); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt index 1503af82545c..e5158e74759c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt @@ -86,7 +86,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { screenBounds, sbHeightPortrait, minLeftPadding, - minRightPadding) + minRightPadding, + isRtl, + dotWidth) var chipBounds = getPrivacyChipBoundingRectForInsets(bounds, dotWidth, chipWidth, isRtl) /* 1080 - 20 (rounded corner) - 30 (chip), @@ -115,7 +117,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { screenBounds, sbHeightLandscape, minLeftPadding, - minRightPadding) + minRightPadding, + isRtl, + dotWidth) chipBounds = getPrivacyChipBoundingRectForInsets(bounds, dotWidth, chipWidth, isRtl) /* 2160 - 20 (rounded corner) - 30 (chip), @@ -146,6 +150,8 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { val sbHeightPortrait = 100 val sbHeightLandscape = 60 val currentRotation = ROTATION_NONE + val isRtl = false + val dotWidth = 10 `when`(dc.boundingRects).thenReturn(listOf(dcBounds)) @@ -164,7 +170,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { screenBounds, sbHeightPortrait, minLeftPadding, - minRightPadding) + minRightPadding, + isRtl, + dotWidth) assertRects(expectedBounds, bounds, currentRotation, targetRotation) @@ -181,7 +189,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { screenBounds, sbHeightLandscape, minLeftPadding, - minRightPadding) + minRightPadding, + isRtl, + dotWidth) assertRects(expectedBounds, bounds, currentRotation, targetRotation) @@ -200,7 +210,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { screenBounds, sbHeightPortrait, minLeftPadding, - minRightPadding) + minRightPadding, + isRtl, + dotWidth) assertRects(expectedBounds, bounds, currentRotation, targetRotation) @@ -208,7 +220,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { targetRotation = ROTATION_SEASCAPE expectedBounds = Rect(minLeftPadding, 0, - screenBounds.height() - dcBounds.height(), + screenBounds.height() - dcBounds.height() - dotWidth, sbHeightLandscape) bounds = calculateInsetsForRotationWithRotatedResources( @@ -218,7 +230,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { screenBounds, sbHeightLandscape, minLeftPadding, - minRightPadding) + minRightPadding, + isRtl, + dotWidth) assertRects(expectedBounds, bounds, currentRotation, targetRotation) } @@ -237,6 +251,8 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { val sbHeightPortrait = 100 val sbHeightLandscape = 60 val currentRotation = ROTATION_NONE + val isRtl = false + val dotWidth = 10 `when`(dc.boundingRects).thenReturn(listOf(dcBounds)) @@ -255,7 +271,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { screenBounds, sbHeightPortrait, minLeftPadding, - minRightPadding) + minRightPadding, + isRtl, + dotWidth) assertRects(expectedBounds, bounds, currentRotation, targetRotation) @@ -272,7 +290,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { screenBounds, sbHeightLandscape, minLeftPadding, - minRightPadding) + minRightPadding, + isRtl, + dotWidth) assertRects(expectedBounds, bounds, currentRotation, targetRotation) @@ -289,14 +309,16 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { screenBounds, sbHeightPortrait, minLeftPadding, - minRightPadding) + minRightPadding, + isRtl, + dotWidth) assertRects(expectedBounds, bounds, currentRotation, targetRotation) targetRotation = ROTATION_SEASCAPE expectedBounds = Rect(minLeftPadding, 0, - screenBounds.height() - dcBounds.height(), + screenBounds.height() - dcBounds.height() - dotWidth, sbHeightLandscape) bounds = calculateInsetsForRotationWithRotatedResources( @@ -306,7 +328,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { screenBounds, sbHeightLandscape, minLeftPadding, - minRightPadding) + minRightPadding, + isRtl, + dotWidth) assertRects(expectedBounds, bounds, currentRotation, targetRotation) } @@ -320,6 +344,8 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { val minRightPadding = 20 val sbHeightPortrait = 100 val sbHeightLandscape = 60 + val isRtl = false + val dotWidth = 10 // THEN content insets should only use rounded corner padding var targetRotation = ROTATION_NONE @@ -335,7 +361,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { screenBounds, sbHeightPortrait, minLeftPadding, - minRightPadding) + minRightPadding, + isRtl, + dotWidth) assertRects(expectedBounds, bounds, currentRotation, targetRotation) targetRotation = ROTATION_LANDSCAPE @@ -351,7 +379,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { screenBounds, sbHeightLandscape, minLeftPadding, - minRightPadding) + minRightPadding, + isRtl, + dotWidth) assertRects(expectedBounds, bounds, currentRotation, targetRotation) targetRotation = ROTATION_UPSIDE_DOWN @@ -367,7 +397,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { screenBounds, sbHeightPortrait, minLeftPadding, - minRightPadding) + minRightPadding, + isRtl, + dotWidth) assertRects(expectedBounds, bounds, currentRotation, targetRotation) targetRotation = ROTATION_LANDSCAPE @@ -383,7 +415,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { screenBounds, sbHeightLandscape, minLeftPadding, - minRightPadding) + minRightPadding, + isRtl, + dotWidth) assertRects(expectedBounds, bounds, currentRotation, targetRotation) } @@ -397,6 +431,8 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { val sbHeightPortrait = 100 val sbHeightLandscape = 60 val currentRotation = ROTATION_NONE + val isRtl = false + val dotWidth = 10 `when`(dc.boundingRects).thenReturn(listOf(dcBounds)) @@ -414,7 +450,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { screenBounds, sbHeightPortrait, minLeftPadding, - minRightPadding) + minRightPadding, + isRtl, + dotWidth) assertRects(expectedBounds, bounds, currentRotation, targetRotation) } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 8205d3579b3b..e6f91a25f168 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -128,6 +128,7 @@ import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.accessibility.magnification.MagnificationController; import com.android.server.accessibility.magnification.MagnificationProcessor; +import com.android.server.accessibility.magnification.MagnificationScaleProvider; import com.android.server.accessibility.magnification.WindowMagnificationManager; import com.android.server.pm.UserManagerInternal; import com.android.server.wm.ActivityTaskManagerInternal; @@ -338,7 +339,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mA11yWindowManager = new AccessibilityWindowManager(mLock, mMainHandler, mWindowManagerService, this, mSecurityPolicy, this, mTraceManager); mA11yDisplayListener = new AccessibilityDisplayListener(mContext, mMainHandler); - mMagnificationController = new MagnificationController(this, mLock, mContext); + mMagnificationController = new MagnificationController(this, mLock, mContext, + new MagnificationScaleProvider(mContext)); mMagnificationProcessor = new MagnificationProcessor(mMagnificationController); init(); } @@ -1364,6 +1366,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } private void switchUser(int userId) { + mMagnificationController.updateUserIdIfNeeded(userId); synchronized (mLock) { if (mCurrentUserId == userId && mInitialized) { return; @@ -1386,8 +1389,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub // The user changed. mCurrentUserId = userId; - - mMagnificationController.updateUserIdIfNeeded(mCurrentUserId); AccessibilityUserState userState = getCurrentUserStateLocked(); readConfigurationForUserStateLocked(userState); @@ -1444,6 +1445,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub synchronized (mLock) { mUserStates.remove(userId); } + getMagnificationController().onUserRemoved(userId); } // Called only during settings restore; currently supports only the owner user diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java index 8f30aa9acc79..c62473db948c 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java @@ -28,10 +28,8 @@ import android.content.Intent; import android.content.IntentFilter; import android.graphics.Rect; import android.graphics.Region; -import android.os.AsyncTask; import android.os.Handler; import android.os.Message; -import android.provider.Settings; import android.text.TextUtils; import android.util.MathUtils; import android.util.Slog; @@ -59,7 +57,8 @@ import java.util.Locale; * holding the current state of magnification and animation, and it handles * communication between the accessibility manager and window manager. * - * Magnification is limited to the range [MIN_SCALE, MAX_SCALE], and can only occur inside the + * Magnification is limited to the range controlled by + * {@link MagnificationScaleProvider#constrainScale(float)}, and can only occur inside the * magnification region. If a value is out of bounds, it will be adjusted to guarantee these * constraints. */ @@ -69,13 +68,9 @@ public class FullScreenMagnificationController { private static final MagnificationAnimationCallback STUB_ANIMATION_CALLBACK = success -> { }; - public static final float MIN_SCALE = 1.0f; - public static final float MAX_SCALE = 8.0f; private static final boolean DEBUG_SET_MAGNIFICATION_SPEC = false; - private static final float DEFAULT_MAGNIFICATION_SCALE = 2.0f; - private final Object mLock; private final ControllerContext mControllerCtx; @@ -84,7 +79,7 @@ public class FullScreenMagnificationController { private final MagnificationInfoChangedCallback mMagnificationInfoChangedCallback; - private int mUserId; + private final MagnificationScaleProvider mScaleProvider; private final long mMainThreadId; @@ -489,7 +484,7 @@ public class FullScreenMagnificationController { return false; } // Constrain scale immediately for use in the pivot calculations. - scale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE); + scale = MagnificationScaleProvider.constrainScale(scale); final Rect viewport = mTempRect; mMagnificationRegion.getBounds(viewport); @@ -557,7 +552,7 @@ public class FullScreenMagnificationController { // Compute changes. boolean changed = false; - final float normScale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE); + final float normScale = MagnificationScaleProvider.constrainScale(scale); if (Float.compare(mCurrentMagnificationSpec.scale, normScale) != 0) { mCurrentMagnificationSpec.scale = normScale; changed = true; @@ -658,12 +653,13 @@ public class FullScreenMagnificationController { */ public FullScreenMagnificationController(@NonNull Context context, @NonNull AccessibilityManagerService ams, @NonNull Object lock, - @NonNull MagnificationInfoChangedCallback magnificationInfoChangedCallback) { + @NonNull MagnificationInfoChangedCallback magnificationInfoChangedCallback, + @NonNull MagnificationScaleProvider scaleProvider) { this(new ControllerContext(context, ams, LocalServices.getService(WindowManagerInternal.class), new Handler(context.getMainLooper()), context.getResources().getInteger(R.integer.config_longAnimTime)), lock, - magnificationInfoChangedCallback); + magnificationInfoChangedCallback, scaleProvider); } /** @@ -672,12 +668,14 @@ public class FullScreenMagnificationController { @VisibleForTesting public FullScreenMagnificationController(@NonNull ControllerContext ctx, @NonNull Object lock, - @NonNull MagnificationInfoChangedCallback magnificationInfoChangedCallback) { + @NonNull MagnificationInfoChangedCallback magnificationInfoChangedCallback, + @NonNull MagnificationScaleProvider scaleProvider) { mControllerCtx = ctx; mLock = lock; mMainThreadId = mControllerCtx.getContext().getMainLooper().getThread().getId(); mScreenStateObserver = new ScreenStateObserver(mControllerCtx.getContext(), this); mMagnificationInfoChangedCallback = magnificationInfoChangedCallback; + mScaleProvider = scaleProvider; } /** @@ -1096,18 +1094,9 @@ public class FullScreenMagnificationController { /** * Persists the default display magnification scale to the current user's settings. */ - public void persistScale() { - // TODO: b/123047354, Need support multi-display? + public void persistScale(int displayId) { final float scale = getScale(Display.DEFAULT_DISPLAY); - final int userId = mUserId; - - new AsyncTask<Void, Void, Void>() { - @Override - protected Void doInBackground(Void... params) { - mControllerCtx.putMagnificationScale(scale, userId); - return null; - } - }.execute(); + mScaleProvider.putScale(scale, displayId); } /** @@ -1117,21 +1106,8 @@ public class FullScreenMagnificationController { * @return the previously persisted magnification scale, or the default * scale if none is available */ - public float getPersistedScale() { - return mControllerCtx.getMagnificationScale(mUserId); - } - - /** - * Sets the currently active user ID. - * - * @param userId the currently active user ID - */ - public void setUserId(int userId) { - if (mUserId == userId) { - return; - } - mUserId = userId; - resetAllIfNeeded(false); + public float getPersistedScale(int displayId) { + return mScaleProvider.getScale(displayId); } /** @@ -1225,7 +1201,11 @@ public class FullScreenMagnificationController { mControllerCtx.getHandler().sendMessage(m); } - private void resetAllIfNeeded(boolean animate) { + /** + * Resets magnification on all displays. + * @param animate reset the magnification with animation + */ + void resetAllIfNeeded(boolean animate) { synchronized (mLock) { for (int i = 0; i < mDisplays.size(); i++) { resetIfNeeded(mDisplays.keyAt(i), animate); @@ -1288,8 +1268,8 @@ public class FullScreenMagnificationController { public String toString() { StringBuilder builder = new StringBuilder(); builder.append("MagnificationController["); - builder.append("mUserId=").append(mUserId); builder.append(", mDisplays=").append(mDisplays); + builder.append(", mScaleProvider=").append(mScaleProvider); builder.append("]"); return builder.toString(); } @@ -1570,23 +1550,6 @@ public class FullScreenMagnificationController { } /** - * Write Settings of magnification scale. - */ - public void putMagnificationScale(float value, int userId) { - Settings.Secure.putFloatForUser(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, value, userId); - } - - /** - * Get Settings of magnification scale. - */ - public float getMagnificationScale(int userId) { - return Settings.Secure.getFloatForUser(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, - DEFAULT_MAGNIFICATION_SCALE, userId); - } - - /** * @return Configuration of animation duration. */ public long getAnimationDuration() { diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java index 8f4a5cb4dad0..935df9934dcb 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java @@ -119,11 +119,11 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH private static final boolean DEBUG_DETECTING = false | DEBUG_ALL; private static final boolean DEBUG_PANNING_SCALING = false | DEBUG_ALL; - // The MIN_SCALE is different from MagnificationController.MIN_SCALE due + // The MIN_SCALE is different from MagnificationScaleProvider.MIN_SCALE due // to AccessibilityService.MagnificationController#setScale() has // different scale range private static final float MIN_SCALE = 2.0f; - private static final float MAX_SCALE = FullScreenMagnificationController.MAX_SCALE; + private static final float MAX_SCALE = MagnificationScaleProvider.MAX_SCALE; @VisibleForTesting final FullScreenMagnificationController mFullScreenMagnificationController; @@ -341,7 +341,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH } public void persistScaleAndTransitionTo(State state) { - mFullScreenMagnificationController.persistScale(); + mFullScreenMagnificationController.persistScale(mDisplayId); clear(); transitionTo(state); } @@ -945,7 +945,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH if (DEBUG_DETECTING) Slog.i(mLogTag, "zoomOn(" + centerX + ", " + centerY + ")"); final float scale = MathUtils.constrain( - mFullScreenMagnificationController.getPersistedScale(), + mFullScreenMagnificationController.getPersistedScale(mDisplayId), MIN_SCALE, MAX_SCALE); mFullScreenMagnificationController.setScaleAndCenter(mDisplayId, scale, centerX, centerY, diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java index 5a6836c2d771..3708c7a422a0 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java @@ -23,11 +23,13 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.content.Context; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.Region; import android.os.SystemClock; +import android.os.UserHandle; import android.provider.Settings; import android.util.Slog; import android.util.SparseArray; @@ -75,12 +77,15 @@ public class MagnificationController implements WindowMagnificationManager.Callb private final SparseArray<DisableMagnificationCallback> mMagnificationEndRunnableSparseArray = new SparseArray(); + private final MagnificationScaleProvider mScaleProvider; private FullScreenMagnificationController mFullScreenMagnificationController; private WindowMagnificationManager mWindowMagnificationMgr; private int mMagnificationCapabilities = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; @GuardedBy("mLock") private int mActivatedMode = ACCESSIBILITY_MAGNIFICATION_MODE_NONE; + // Track the active user to reset the magnification and get the associated user settings. + private @UserIdInt int mUserId = UserHandle.USER_SYSTEM; @GuardedBy("mLock") private boolean mImeWindowVisible = false; private long mWindowModeEnabledTime = 0; @@ -98,17 +103,19 @@ public class MagnificationController implements WindowMagnificationManager.Callb } public MagnificationController(AccessibilityManagerService ams, Object lock, - Context context) { + Context context, MagnificationScaleProvider scaleProvider) { mAms = ams; mLock = lock; mContext = context; + mScaleProvider = scaleProvider; } @VisibleForTesting public MagnificationController(AccessibilityManagerService ams, Object lock, Context context, FullScreenMagnificationController fullScreenMagnificationController, - WindowMagnificationManager windowMagnificationManager) { - this(ams, lock, context); + WindowMagnificationManager windowMagnificationManager, + MagnificationScaleProvider scaleProvider) { + this(ams, lock, context, scaleProvider); mFullScreenMagnificationController = fullScreenMagnificationController; mWindowMagnificationMgr = windowMagnificationManager; } @@ -194,7 +201,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb final FullScreenMagnificationController screenMagnificationController = getFullScreenMagnificationController(); final WindowMagnificationManager windowMagnificationMgr = getWindowMagnificationMgr(); - final float scale = windowMagnificationMgr.getPersistedScale(); + final float scale = mScaleProvider.getScale(displayId); final DisableMagnificationCallback animationEndCallback = new DisableMagnificationCallback(transitionCallBack, displayId, targetMode, scale, magnificationCenter); @@ -313,13 +320,23 @@ public class MagnificationController implements WindowMagnificationManager.Callb * @param userId the currently active user ID */ public void updateUserIdIfNeeded(int userId) { + if (mUserId == userId) { + return; + } + mUserId = userId; + final FullScreenMagnificationController fullMagnificationController; + final WindowMagnificationManager windowMagnificationManager; synchronized (mLock) { - if (mFullScreenMagnificationController != null) { - mFullScreenMagnificationController.setUserId(userId); - } - if (mWindowMagnificationMgr != null) { - mWindowMagnificationMgr.setUserId(userId); - } + fullMagnificationController = mFullScreenMagnificationController; + windowMagnificationManager = mWindowMagnificationMgr; + } + + mScaleProvider.onUserChanged(userId); + if (fullMagnificationController != null) { + fullMagnificationController.resetAllIfNeeded(false); + } + if (windowMagnificationManager != null) { + windowMagnificationManager.disableAllWindowMagnifiers(); } } @@ -337,6 +354,14 @@ public class MagnificationController implements WindowMagnificationManager.Callb mWindowMagnificationMgr.onDisplayRemoved(displayId); } } + mScaleProvider.onDisplayRemoved(displayId); + } + + /** + * Called when the given user is removed. + */ + public void onUserRemoved(int userId) { + mScaleProvider.onUserRemoved(userId); } public void setMagnificationCapabilities(int capabilities) { @@ -378,8 +403,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb synchronized (mLock) { if (mFullScreenMagnificationController == null) { mFullScreenMagnificationController = new FullScreenMagnificationController(mContext, - mAms, mLock, this); - mFullScreenMagnificationController.setUserId(mAms.getCurrentUserIdLocked()); + mAms, mLock, this, mScaleProvider); } } return mFullScreenMagnificationController; @@ -404,7 +428,8 @@ public class MagnificationController implements WindowMagnificationManager.Callb synchronized (mLock) { if (mWindowMagnificationMgr == null) { mWindowMagnificationMgr = new WindowMagnificationManager(mContext, - mAms.getCurrentUserIdLocked(), this, mAms.getTraceManager()); + mUserId, this, mAms.getTraceManager(), + mScaleProvider); } return mWindowMagnificationMgr; } diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationScaleProvider.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationScaleProvider.java new file mode 100644 index 000000000000..8e1aa38be9e8 --- /dev/null +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationScaleProvider.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.accessibility.magnification; + +import android.content.Context; +import android.os.UserHandle; +import android.provider.Settings; +import android.util.MathUtils; +import android.util.SparseArray; +import android.view.Display; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.BackgroundThread; + +/** + * Supplies setter/getter of the magnification scale for the given display. Only the value of the + * default play is persisted. It also constraints the range of applied magnification scale between + * [MIN_SCALE, MAX_SCALE] which is consistent with the range provided by + * {@code AccessibilityService.MagnificationController#setScale()}. + */ +public class MagnificationScaleProvider { + + @VisibleForTesting + protected static final float DEFAULT_MAGNIFICATION_SCALE = 2.0f; + public static final float MIN_SCALE = 1.0f; + public static final float MAX_SCALE = 8.0f; + + private final Context mContext; + // Stores the scale for non-default displays. + @GuardedBy("mLock") + private final SparseArray<SparseArray<Float>> mUsersScales = new SparseArray(); + private int mCurrentUserId = UserHandle.USER_SYSTEM; + private final Object mLock = new Object(); + + public MagnificationScaleProvider(Context context) { + mContext = context; + } + + /** + * Stores the user settings scale associated to the given display. Only the scale of the + * default display is persistent. + * + * @param scale the magnification scale + * @param displayId the id of the display + */ + void putScale(float scale, int displayId) { + if (displayId == Display.DEFAULT_DISPLAY) { + BackgroundThread.getHandler().post( + () -> Settings.Secure.putFloatForUser(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, scale, + mCurrentUserId)); + } else { + synchronized (mLock) { + getScalesWithCurrentUser().put(displayId, scale); + } + } + } + + /** + * Gets the user settings scale with the given display. + * + * @param displayId the id of the display + * @return the magnification scale. + */ + float getScale(int displayId) { + if (displayId == Display.DEFAULT_DISPLAY) { + return Settings.Secure.getFloatForUser(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, + DEFAULT_MAGNIFICATION_SCALE, mCurrentUserId); + } else { + synchronized (mLock) { + return getScalesWithCurrentUser().get(displayId, DEFAULT_MAGNIFICATION_SCALE); + } + } + } + + + @GuardedBy("mLock") + private SparseArray<Float> getScalesWithCurrentUser() { + SparseArray<Float> scales = mUsersScales.get(mCurrentUserId); + if (scales == null) { + scales = new SparseArray<>(); + mUsersScales.put(mCurrentUserId, scales); + } + + return scales; + } + + void onUserChanged(int userId) { + synchronized (mLock) { + mCurrentUserId = userId; + } + } + + void onUserRemoved(int userId) { + synchronized (mLock) { + mUsersScales.remove(userId); + } + } + + void onDisplayRemoved(int displayId) { + synchronized (mLock) { + final int userCounts = mUsersScales.size(); + for (int i = userCounts - 1; i >= 0; i--) { + mUsersScales.get(i).remove(displayId); + } + } + } + + @Override + public String toString() { + synchronized (mLock) { + return "MagnificationScaleProvider{" + + "mCurrentUserId=" + mCurrentUserId + + "Scale on the default display=" + getScale(Display.DEFAULT_DISPLAY) + + "Scales on non-default displays=" + getScalesWithCurrentUser() + + '}'; + } + } + + static float constrainScale(float scale) { + return MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE); + } +} diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java index bc61284f6084..7d8f545b65c3 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java @@ -69,7 +69,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl //Ensure the range has consistency with FullScreenMagnificationGestureHandler. private static final float MIN_SCALE = 2.0f; - private static final float MAX_SCALE = WindowMagnificationManager.MAX_SCALE; + private static final float MAX_SCALE = MagnificationScaleProvider.MAX_SCALE; private final WindowMagnificationManager mWindowMagnificationMgr; @VisibleForTesting @@ -177,8 +177,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl } final float scale = MathUtils.constrain( - mWindowMagnificationMgr.getPersistedScale(), - MIN_SCALE, MAX_SCALE); + mWindowMagnificationMgr.getPersistedScale(mDisplayId), MIN_SCALE, MAX_SCALE); mWindowMagnificationMgr.enableWindowMagnification(mDisplayId, scale, centerX, centerY); } diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java index 7a111d80b42e..ce7ba7568b6e 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java @@ -29,8 +29,6 @@ import android.graphics.Rect; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; -import android.provider.Settings; -import android.util.MathUtils; import android.util.Slog; import android.util.SparseArray; import android.view.MotionEvent; @@ -40,7 +38,6 @@ import android.view.accessibility.MagnificationAnimationCallback; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.os.BackgroundThread; import com.android.server.LocalServices; import com.android.server.accessibility.AccessibilityTraceManager; import com.android.server.statusbar.StatusBarManagerInternal; @@ -49,6 +46,8 @@ import com.android.server.statusbar.StatusBarManagerInternal; * A class to manipulate window magnification through {@link WindowMagnificationConnectionWrapper} * create by {@link #setConnection(IWindowMagnificationConnection)}. To set the connection with * SysUI, call {@code StatusBarManagerInternal#requestWindowMagnificationConnection(boolean)}. + * The applied magnification scale is constrained by + * {@link MagnificationScaleProvider#constrainScale(float)} */ public class WindowMagnificationManager implements PanningScalingHandler.MagnificationDelegate { @@ -57,10 +56,6 @@ public class WindowMagnificationManager implements private static final String TAG = "WindowMagnificationMgr"; - //Ensure the range has consistency with full screen. - static final float MAX_SCALE = FullScreenMagnificationController.MAX_SCALE; - static final float MIN_SCALE = FullScreenMagnificationController.MIN_SCALE; - private final Object mLock = new Object(); private final Context mContext; @VisibleForTesting @@ -71,7 +66,6 @@ public class WindowMagnificationManager implements private ConnectionCallback mConnectionCallback; @GuardedBy("mLock") private SparseArray<WindowMagnifier> mWindowMagnifiers = new SparseArray<>(); - private int mUserId; private boolean mReceiverRegistered = false; @VisibleForTesting @@ -116,13 +110,14 @@ public class WindowMagnificationManager implements private final Callback mCallback; private final AccessibilityTraceManager mTrace; + private final MagnificationScaleProvider mScaleProvider; public WindowMagnificationManager(Context context, int userId, @NonNull Callback callback, - AccessibilityTraceManager trace) { + AccessibilityTraceManager trace, MagnificationScaleProvider scaleProvider) { mContext = context; - mUserId = userId; mCallback = callback; mTrace = trace; + mScaleProvider = scaleProvider; } /** @@ -159,15 +154,6 @@ public class WindowMagnificationManager implements } /** - * Sets the currently active user ID. - * - * @param userId the currently active user ID - */ - public void setUserId(int userId) { - mUserId = userId; - } - - /** * @return {@code true} if {@link IWindowMagnificationConnection} is available */ public boolean isConnected() { @@ -219,13 +205,18 @@ public class WindowMagnificationManager implements return true; } - @GuardedBy("mLock") - private void disableAllWindowMagnifiers() { - for (int i = 0; i < mWindowMagnifiers.size(); i++) { - final WindowMagnifier magnifier = mWindowMagnifiers.valueAt(i); - magnifier.disableWindowMagnificationInternal(null); + /** + * Disables window magnifier on all displays without animation. + */ + void disableAllWindowMagnifiers() { + synchronized (mLock) { + for (int i = 0; i < mWindowMagnifiers.size(); i++) { + final WindowMagnifier magnifier = mWindowMagnifiers.valueAt(i); + magnifier.disableWindowMagnificationInternal(null); + } + mWindowMagnifiers.clear(); } - mWindowMagnifiers.clear(); + } private void resetWindowMagnifiers() { @@ -378,29 +369,24 @@ public class WindowMagnificationManager implements } /** - * Retrieves a previously persisted magnification scale from the current - * user's settings. + * Retrieves a previously magnification scale from the current + * user's settings. Only the value of the default display is persisted. * - * @return the previously persisted magnification scale, or the default + * @return the previously magnification scale, or the default * scale if none is available */ - float getPersistedScale() { - return Settings.Secure.getFloatForUser(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, - MIN_SCALE, mUserId); + float getPersistedScale(int displayId) { + return mScaleProvider.getScale(displayId); } /** - * Persists the default display magnification scale to the current user's settings. + * Persists the default display magnification scale to the current user's settings. Only the + * value of the default display is persisted in user's settings. */ void persistScale(int displayId) { - float scale = getScale(displayId); if (scale != 1.0f) { - BackgroundThread.getHandler().post(() -> { - Settings.Secure.putFloatForUser(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, scale, mUserId); - }); + mScaleProvider.putScale(scale, displayId); } } @@ -511,7 +497,7 @@ public class WindowMagnificationManager implements * * @param displayId The logical display id. */ - void onDisplayRemoved(int displayId) { + public void onDisplayRemoved(int displayId) { disableWindowMagnification(displayId, true); } @@ -613,7 +599,7 @@ public class WindowMagnificationManager implements private static class WindowMagnifier { private final int mDisplayId; - private float mScale = MIN_SCALE; + private float mScale = MagnificationScaleProvider.MIN_SCALE; private boolean mEnabled; private final WindowMagnificationManager mWindowMagnificationManager; @@ -633,7 +619,7 @@ public class WindowMagnificationManager implements if (mEnabled) { return false; } - final float normScale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE); + final float normScale = MagnificationScaleProvider.constrainScale(scale); if (mWindowMagnificationManager.enableWindowMagnificationInternal(mDisplayId, normScale, centerX, centerY, animationCallback)) { mScale = normScale; @@ -664,7 +650,7 @@ public class WindowMagnificationManager implements if (!mEnabled) { return; } - final float normScale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE); + final float normScale = MagnificationScaleProvider.constrainScale(scale); if (Float.compare(mScale, normScale) != 0 && mWindowMagnificationManager.setScaleInternal(mDisplayId, scale)) { mScale = normScale; diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index c32543ae5c13..78d9095853f7 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -147,7 +147,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku OnCrossProfileWidgetProvidersChangeListener { private static final String TAG = "AppWidgetServiceImpl"; - private static boolean DEBUG = false; + private static final boolean DEBUG = false; private static final String OLD_KEYGUARD_HOST_PACKAGE = "android"; private static final String NEW_KEYGUARD_HOST_PACKAGE = "com.android.keyguard"; diff --git a/services/core/java/android/content/pm/OWNERS b/services/core/java/android/content/pm/OWNERS index 5eed0b509688..39931407ec1f 100644 --- a/services/core/java/android/content/pm/OWNERS +++ b/services/core/java/android/content/pm/OWNERS @@ -1 +1 @@ -include /core/java/android/content/pm/OWNERS
\ No newline at end of file +include /PACKAGE_MANAGER_OWNERS
\ No newline at end of file diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index 1e608f5c1240..0146aa82a217 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -81,8 +81,6 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import java.util.NoSuchElementException; import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; @@ -1435,11 +1433,7 @@ public final class BatteryService extends SystemService { */ public static final class HealthServiceWrapper { private static final String TAG = "HealthServiceWrapper"; - public static final String INSTANCE_HEALTHD = "backup"; public static final String INSTANCE_VENDOR = "default"; - // All interesting instances, sorted by priority high -> low. - private static final List<String> sAllInstances = - Arrays.asList(INSTANCE_VENDOR, INSTANCE_HEALTHD); private final IServiceNotification mNotification = new Notification(); private final HandlerThread mHandlerThread = new HandlerThread("HealthServiceHwbinder"); @@ -1471,8 +1465,8 @@ public final class BatteryService extends SystemService { } /** - * Start monitoring registration of new IHealth services. Only instances that are in - * {@code sAllInstances} and in device / framework manifest are used. This function should + * Start monitoring registration of new IHealth services. Only instance + * {@link #INSTANCE_VENDOR} and in device / framework manifest are used. This function should * only be called once. * * mCallback.onRegistration() is called synchronously (aka in init thread) before @@ -1481,7 +1475,7 @@ public final class BatteryService extends SystemService { * @throws RemoteException transaction error when talking to IServiceManager * @throws NoSuchElementException if one of the following cases: * - No service manager; - * - none of {@code sAllInstances} are in manifests (i.e. not + * - {@link #INSTANCE_VENDOR} is not in manifests (i.e. not * available on this device), or none of these instances are available to current * process. * @throws NullPointerException when supplier is null @@ -1499,26 +1493,23 @@ public final class BatteryService extends SystemService { // Initialize mLastService and call callback for the first time (in init thread) IHealth newService = null; - for (String name : sAllInstances) { - traceBegin("HealthInitGetService_" + name); - try { - newService = healthSupplier.get(name); - } catch (NoSuchElementException ex) { - /* ignored, handled below */ - } finally { - traceEnd(); - } - if (newService != null) { - mInstanceName = name; - mLastService.set(newService); - break; - } + traceBegin("HealthInitGetService_" + INSTANCE_VENDOR); + try { + newService = healthSupplier.get(INSTANCE_VENDOR); + } catch (NoSuchElementException ex) { + /* ignored, handled below */ + } finally { + traceEnd(); + } + if (newService != null) { + mInstanceName = INSTANCE_VENDOR; + mLastService.set(newService); } if (mInstanceName == null || newService == null) { throw new NoSuchElementException(String.format( - "No IHealth service instance among %s is available. Perhaps no permission?", - sAllInstances.toString())); + "IHealth service instance %s isn't available. Perhaps no permission?", + INSTANCE_VENDOR)); } if (callback != null) { diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java index 39321bfe6435..99232746cea1 100644 --- a/services/core/java/com/android/server/SystemService.java +++ b/services/core/java/com/android/server/SystemService.java @@ -301,17 +301,20 @@ public abstract class SystemService { protected void dumpSupportedUsers(@NonNull PrintWriter pw, @NonNull String prefix) { final List<UserInfo> allUsers = UserManager.get(mContext).getUsers(); final List<Integer> supportedUsers = new ArrayList<>(allUsers.size()); - for (UserInfo user : allUsers) { - supportedUsers.add(user.id); + for (int i = 0; i < allUsers.size(); i++) { + final UserInfo user = allUsers.get(i); + if (isUserSupported(new TargetUser(user))) { + supportedUsers.add(user.id); + } } - if (allUsers.isEmpty()) { + if (supportedUsers.isEmpty()) { pw.print(prefix); pw.println("No supported users"); - } else { - final int size = supportedUsers.size(); - pw.print(prefix); pw.print(size); pw.print(" supported user"); - if (size > 1) pw.print("s"); - pw.print(": "); pw.println(supportedUsers); + return; } + final int size = supportedUsers.size(); + pw.print(prefix); pw.print(size); pw.print(" supported user"); + if (size > 1) pw.print("s"); + pw.print(": "); pw.println(supportedUsers); } /** diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java index 031f6eeeca5f..61b8ded60db7 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java @@ -168,6 +168,10 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> return Utils.isKeyguard(getContext(), getOwnerString()); } + private boolean isSettings() { + return Utils.isSettings(getContext(), getOwnerString()); + } + @Override protected boolean isCryptoOperation() { return mOperationId != 0; @@ -499,6 +503,8 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> protected int getShowOverlayReason() { if (isKeyguard()) { return BiometricOverlayConstants.REASON_AUTH_KEYGUARD; + } else if (isSettings()) { + return BiometricOverlayConstants.REASON_AUTH_SETTINGS; } else if (isBiometricPrompt()) { return BiometricOverlayConstants.REASON_AUTH_BP; } else { diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java index ca051e9e9bf4..e4d5fba3a471 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java @@ -229,6 +229,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp @Override public void onLockoutTimed(long durationMillis) { + super.onLockoutTimed(durationMillis); mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_TIMED); // Lockout metrics are logged as an error code. final int error = BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT; @@ -246,6 +247,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp @Override public void onLockoutPermanent() { + super.onLockoutPermanent(); mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_PERMANENT); // Lockout metrics are logged as an error code. final int error = BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT_PERMANENT; diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java index 147050cd271f..2f22d33f552a 100644 --- a/services/core/java/com/android/server/display/DisplayPowerState.java +++ b/services/core/java/com/android/server/display/DisplayPowerState.java @@ -48,7 +48,7 @@ import java.io.PrintWriter; final class DisplayPowerState { private static final String TAG = "DisplayPowerState"; - private static boolean DEBUG = false; + private static final boolean DEBUG = false; private static String COUNTER_COLOR_FADE = "ColorFadeLevel"; private final Handler mHandler; diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index f356c36f7468..3aa2f420d11f 100755 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -208,6 +208,12 @@ abstract class HdmiCecLocalDevice { void init() { assertRunOnServiceThread(); mPreferredAddress = getPreferredAddress(); + if (mHandler.hasMessages(MSG_DISABLE_DEVICE_TIMEOUT)) { + // Remove and trigger the queued message for clearing all actions when going to standby. + // This is necessary because the device may wake up before the message is triggered. + mHandler.removeMessages(MSG_DISABLE_DEVICE_TIMEOUT); + handleDisableDeviceTimeout(); + } mPendingActionClearedCallback = null; } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index b5bb8bd3ae1a..69f7af23fe4c 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -3166,7 +3166,7 @@ public class HdmiControlService extends SystemService { Slog.v(TAG, "On standby-action cleared:" + device.mDeviceType); devices.remove(device); if (devices.isEmpty()) { - onStandbyCompleted(standbyAction); + onPendingActionsCleared(standbyAction); // We will not clear local devices here, since some OEM/SOC will keep passing // the received packets until the application processor enters to the sleep // actually. @@ -3227,10 +3227,17 @@ public class HdmiControlService extends SystemService { mHdmiCecNetwork.clearLocalDevices(); } + /** + * Normally called after all devices have cleared their pending actions, to execute the final + * phase of the standby flow. + * + * This can also be called during wakeup, when pending actions are cleared after failing to be + * cleared during standby. In this case, it does not execute the standby flow. + */ @ServiceThreadOnly - private void onStandbyCompleted(int standbyAction) { + private void onPendingActionsCleared(int standbyAction) { assertRunOnServiceThread(); - Slog.v(TAG, "onStandbyCompleted"); + Slog.v(TAG, "onPendingActionsCleared"); if (!mPowerStatusController.isPowerStatusTransientToStandby()) { return; diff --git a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java index d285c437a3df..487346763f0f 100644 --- a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java +++ b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java @@ -40,7 +40,7 @@ import java.util.Set; * Monitors the state changes of audio players. */ class AudioPlayerStateMonitor { - private static boolean DEBUG = MediaSessionService.DEBUG; + private static final boolean DEBUG = MediaSessionService.DEBUG; private static String TAG = "AudioPlayerStateMonitor"; private static AudioPlayerStateMonitor sInstance; diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS index 3233819b543f..babe21c87a86 100644 --- a/services/core/java/com/android/server/pm/OWNERS +++ b/services/core/java/com/android/server/pm/OWNERS @@ -3,11 +3,9 @@ hackbod@google.com jsharkey@android.com jsharkey@google.com narayan@google.com -patb@google.com svetoslavganov@android.com svetoslavganov@google.com -toddke@android.com -toddke@google.com +include /PACKAGE_MANAGER_OWNERS # apex support per-file ApexManager.java = dariofreni@google.com, ioffe@google.com, olilan@google.com diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index c953166ba814..89e47b9cbe04 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -8916,7 +8916,8 @@ public class PackageManagerService extends IPackageManager.Stub * return {@code true} if any one application belongs to the shared user ID meets the criteria. */ boolean canQueryPackage(int callingUid, @Nullable String targetPackageName) { - if (targetPackageName == null) { + // Since getSettingLPr returns null for ROOT_UID, add an extra check for it here. + if (callingUid == Process.ROOT_UID || targetPackageName == null) { return true; } synchronized (mLock) { diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING index c8deffbf257a..d54acb7d6bd6 100644 --- a/services/core/java/com/android/server/pm/TEST_MAPPING +++ b/services/core/java/com/android/server/pm/TEST_MAPPING @@ -21,9 +21,6 @@ "name": "CtsAppEnumerationTestCases" }, { - "name": "AppEnumerationInternalTests" - }, - { "name": "CtsMatchFlagTestCases" }, { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 2cb9d76b6846..0590e22f012d 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -2937,6 +2937,24 @@ public class PhoneWindowManager implements WindowManagerPolicy { Slog.wtf(TAG, "KEYCODE_VOICE_ASSIST should be handled in" + " interceptKeyBeforeQueueing"); return key_consumed; + case KeyEvent.KEYCODE_VIDEO_APP_1: + case KeyEvent.KEYCODE_VIDEO_APP_2: + case KeyEvent.KEYCODE_VIDEO_APP_3: + case KeyEvent.KEYCODE_VIDEO_APP_4: + case KeyEvent.KEYCODE_VIDEO_APP_5: + case KeyEvent.KEYCODE_VIDEO_APP_6: + case KeyEvent.KEYCODE_VIDEO_APP_7: + case KeyEvent.KEYCODE_VIDEO_APP_8: + case KeyEvent.KEYCODE_FEATURED_APP_1: + case KeyEvent.KEYCODE_FEATURED_APP_2: + case KeyEvent.KEYCODE_FEATURED_APP_3: + case KeyEvent.KEYCODE_FEATURED_APP_4: + case KeyEvent.KEYCODE_DEMO_APP_1: + case KeyEvent.KEYCODE_DEMO_APP_2: + case KeyEvent.KEYCODE_DEMO_APP_3: + case KeyEvent.KEYCODE_DEMO_APP_4: + Slog.wtf(TAG, "KEYCODE_APP_X should be handled in interceptKeyBeforeQueueing"); + return key_consumed; case KeyEvent.KEYCODE_SYSRQ: if (down && repeatCount == 0) { mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN); @@ -4040,6 +4058,26 @@ public class PhoneWindowManager implements WindowManagerPolicy { } break; } + case KeyEvent.KEYCODE_VIDEO_APP_1: + case KeyEvent.KEYCODE_VIDEO_APP_2: + case KeyEvent.KEYCODE_VIDEO_APP_3: + case KeyEvent.KEYCODE_VIDEO_APP_4: + case KeyEvent.KEYCODE_VIDEO_APP_5: + case KeyEvent.KEYCODE_VIDEO_APP_6: + case KeyEvent.KEYCODE_VIDEO_APP_7: + case KeyEvent.KEYCODE_VIDEO_APP_8: + case KeyEvent.KEYCODE_FEATURED_APP_1: + case KeyEvent.KEYCODE_FEATURED_APP_2: + case KeyEvent.KEYCODE_FEATURED_APP_3: + case KeyEvent.KEYCODE_FEATURED_APP_4: + case KeyEvent.KEYCODE_DEMO_APP_1: + case KeyEvent.KEYCODE_DEMO_APP_2: + case KeyEvent.KEYCODE_DEMO_APP_3: + case KeyEvent.KEYCODE_DEMO_APP_4: { + // Just drop if keys are not intercepted for direct key. + result &= ~ACTION_PASS_TO_USER; + break; + } } // Intercept the Accessibility keychord (CTRL + ALT + Z) for keyboard users. diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index 0fcf458ba535..0c7849468b96 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -2069,7 +2069,7 @@ public class StatsPullAtomService extends SystemService { if (info == null) { return StatsManager.PULL_SKIP; } - pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, info.getTimeStamp(), + pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, info.getTimestampMillis(), info.getBluetoothStackState(), info.getControllerTxTimeMillis(), info.getControllerRxTimeMillis(), info.getControllerIdleTimeMillis(), info.getControllerEnergyUsed())); diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java index 0f37450c24c9..e98fa28634a4 100644 --- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java +++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java @@ -86,6 +86,9 @@ public final class TextClassificationManagerService extends ITextClassifierServi private static final String LOG_TAG = "TextClassificationManagerService"; + // TODO: consider using device config to control it. + private static final boolean DEBUG = false; + private static final ITextClassifierCallback NO_OP_CALLBACK = new ITextClassifierCallback() { @Override public void onSuccess(Bundle result) {} @@ -175,8 +178,6 @@ public final class TextClassificationManagerService extends ITextClassifierServi private final String mDefaultTextClassifierPackage; @Nullable private final String mSystemTextClassifierPackage; - // TODO: consider using device config to control it. - private boolean DEBUG = false; private TextClassificationManagerService(Context context) { mContext = Objects.requireNonNull(context); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 50f3d8b25c92..3de4cdc930e5 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -4109,19 +4109,40 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * conditions a) above. * Multi-windowing mode will be exited if {@code true} is returned. */ - boolean canShowWhenLocked() { - if (!inPinnedWindowingMode() && (mShowWhenLocked || containsShowWhenLockedWindow())) { + private static boolean canShowWhenLocked(ActivityRecord r) { + if (r == null || r.getTaskFragment() == null) { + return false; + } + if (!r.inPinnedWindowingMode() && (r.mShowWhenLocked || r.containsShowWhenLockedWindow())) { return true; - } else if (mInheritShownWhenLocked) { - final ActivityRecord r = task.getActivityBelow(this); - return r != null && !r.inPinnedWindowingMode() && (r.mShowWhenLocked - || r.containsShowWhenLockedWindow()); + } else if (r.mInheritShownWhenLocked) { + final ActivityRecord activity = r.getTaskFragment().getActivityBelow(r); + return activity != null && !activity.inPinnedWindowingMode() + && (activity.mShowWhenLocked || activity.containsShowWhenLockedWindow()); } else { return false; } } /** + * Determines if the activity can show while lock-screen is displayed. System displays + * activities while lock-screen is displayed only if all activities + * {@link #canShowWhenLocked(ActivityRecord)}. + * @see #canShowWhenLocked(ActivityRecord) + */ + boolean canShowWhenLocked() { + final TaskFragment taskFragment = getTaskFragment(); + if (taskFragment != null && taskFragment.getAdjacentTaskFragment() != null + && taskFragment.isEmbedded()) { + final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment(); + final ActivityRecord r = adjacentTaskFragment.getTopNonFinishingActivity(); + return canShowWhenLocked(this) && canShowWhenLocked(r); + } else { + return canShowWhenLocked(this); + } + } + + /** * @return Whether we are allowed to show non-starting windows at the moment. We disallow * showing windows during transitions in case we have windows that have wide-color-gamut * color mode set to avoid jank in the middle of the transition. diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 25a5708f3b4b..52546affa51e 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -804,13 +804,16 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp }; private final Consumer<WindowState> mPerformLayout = w -> { + if (w.mLayoutAttached || w.skipLayout()) { + return; + } + // Don't do layout of a window if it is not visible, or soon won't be visible, to avoid // wasting time and funky changes while a window is animating away. final boolean gone = w.isGoneForLayout(); - if (DEBUG_LAYOUT && !w.mLayoutAttached) { + if (DEBUG_LAYOUT) { Slog.v(TAG, "1ST PASS " + w + ": gone=" + gone + " mHaveFrame=" + w.mHaveFrame - + " mLayoutAttached=" + w.mLayoutAttached + " config reported=" + w.isLastConfigReportedToClient()); final ActivityRecord activity = w.mActivityRecord; if (gone) Slog.v(TAG, " GONE: mViewVisibility=" + w.mViewVisibility @@ -826,7 +829,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // If this view is GONE, then skip it -- keep the current frame, and let the caller know // so they can ignore it if they want. (We do the normal layout for INVISIBLE windows, // since that means "perform layout as normal, just don't display"). - if ((!gone || !w.mHaveFrame || w.mLayoutNeeded) && !w.mLayoutAttached) { + if (!gone || !w.mHaveFrame || w.mLayoutNeeded) { if (mTmpInitial) { w.resetContentChanged(); } @@ -853,34 +856,34 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrame() - + " mContainingFrame=" + w.getContainingFrame() + + " mParentFrame=" + w.getParentFrame() + " mDisplayFrame=" + w.getDisplayFrame()); } }; private final Consumer<WindowState> mPerformLayoutAttached = w -> { - if (w.mLayoutAttached) { - if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + w + " mHaveFrame=" + w.mHaveFrame - + " mViewVisibility=" + w.mViewVisibility - + " mRelayoutCalled=" + w.mRelayoutCalled); - // If this view is GONE, then skip it -- keep the current frame, and let the caller - // know so they can ignore it if they want. (We do the normal layout for INVISIBLE - // windows, since that means "perform layout as normal, just don't display"). - if ((w.mViewVisibility != GONE && w.mRelayoutCalled) || !w.mHaveFrame - || w.mLayoutNeeded) { - if (mTmpInitial) { - //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial"); - w.resetContentChanged(); - } - w.mSurfacePlacementNeeded = true; - w.mLayoutNeeded = false; - w.prelayout(); - getDisplayPolicy().layoutWindowLw(w, w.getParentWindow(), mDisplayFrames); - w.mLayoutSeq = mLayoutSeq; - if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrame() - + " mContainingFrame=" + w.getContainingFrame() - + " mDisplayFrame=" + w.getDisplayFrame()); + if (!w.mLayoutAttached || w.skipLayout()) { + return; + } + if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + w + " mHaveFrame=" + w.mHaveFrame + + " mViewVisibility=" + w.mViewVisibility + + " mRelayoutCalled=" + w.mRelayoutCalled); + // If this view is GONE, then skip it -- keep the current frame, and let the caller + // know so they can ignore it if they want. (We do the normal layout for INVISIBLE + // windows, since that means "perform layout as normal, just don't display"). + if ((w.mViewVisibility != GONE && w.mRelayoutCalled) || !w.mHaveFrame + || w.mLayoutNeeded) { + if (mTmpInitial) { + w.resetContentChanged(); } + w.mSurfacePlacementNeeded = true; + w.mLayoutNeeded = false; + w.prelayout(); + getDisplayPolicy().layoutWindowLw(w, w.getParentWindow(), mDisplayFrames); + w.mLayoutSeq = mLayoutSeq; + if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrame() + + " mParentFrame=" + w.getParentFrame() + + " mDisplayFrame=" + w.getDisplayFrame()); } }; diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 253b3a529f67..750c890ec066 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -43,12 +43,12 @@ import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_B import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS; import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS; import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS; +import static android.view.WindowLayout.UNSPECIFIED_LENGTH; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON; import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN; -import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; @@ -65,7 +65,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL; -import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; @@ -115,6 +114,7 @@ import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Region; +import android.gui.DropInputMode; import android.hardware.power.Boost; import android.os.Handler; import android.os.IBinder; @@ -962,6 +962,20 @@ public class DisplayPolicy { } /** + * Add additional policy if needed to ensure the window or its children should not receive any + * input. + */ + public void setDropInputModePolicy(WindowState win, LayoutParams attrs) { + if (attrs.type == TYPE_TOAST + && (attrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) == 0) { + // Toasts should not receive input. These windows should not have any children, so + // force this hierarchy of windows to drop all input. + mService.mTransactionFactory.get() + .setDropInputMode(win.getSurfaceControl(), DropInputMode.ALL).apply(); + } + } + + /** * Check if a window can be added to the system. * * Currently enforces that two window types are singletons per display: @@ -1704,10 +1718,6 @@ public class DisplayPolicy { layoutStatusBar(displayFrames, mBarContentFrames.get(TYPE_STATUS_BAR)); return; } - if (win.mActivityRecord != null && win.mActivityRecord.mWaitForEnteringPinnedMode) { - // Skip layout of the window when in transition to pip mode. - return; - } final WindowManager.LayoutParams attrs = win.getLayoutingAttrs(displayFrames.mRotation); final int type = attrs.type; @@ -1719,37 +1729,50 @@ public class DisplayPolicy { final Rect pf = windowFrames.mParentFrame; final Rect df = windowFrames.mDisplayFrame; + final Rect f = windowFrames.mFrame; final Rect attachedWindowFrame = attached != null ? attached.getFrame() : null; sTmpLastParentFrame.set(pf); - // Override the bounds in window token has many side effects. Directly use the display - // frame set for the simulated layout for this case. - final Rect winBounds = windowFrames.mIsSimulatingDecorWindow ? df : win.getBounds(); + final Rect winBounds; + final int requestedWidth; + final int requestedHeight; + if (windowFrames.mIsSimulatingDecorWindow) { + // Override the bounds in window token has many side effects. Directly use the display + // frame set for the simulated layout. + winBounds = df; + + // The view hierarchy has not been measured in the simulated layout. Use + // UNSPECIFIED_LENGTH as the requested width and height so that WindowLayout will choose + // the proper values in this case. + requestedWidth = UNSPECIFIED_LENGTH; + requestedHeight = UNSPECIFIED_LENGTH; + } else { + winBounds = win.getBounds(); + requestedWidth = win.mRequestedWidth; + requestedHeight = win.mRequestedHeight; + } final boolean clippedByDisplayCutout = mWindowLayout.computeWindowFrames(attrs, - win.getInsetsState(), displayFrames.mDisplayCutoutSafe, winBounds, - win.getRequestedVisibilities(), attachedWindowFrame, df, pf); + win.getInsetsState(), displayFrames.mDisplayCutoutSafe, + winBounds, win.getWindowingMode(), requestedWidth, requestedHeight, + win.getRequestedVisibilities(), attachedWindowFrame, win.mGlobalScale, + df, pf, f); windowFrames.setParentFrameWasClippedByDisplayCutout(clippedByDisplayCutout); - // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it. - // Also, we don't allow windows in multi-window mode to extend out of the screen. - if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR - && !win.inMultiWindowMode()) { - df.left = df.top = -10000; - df.right = df.bottom = 10000; - } - if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle() + ": sim=#" + Integer.toHexString(sim) + " attach=" + attached + " type=" + type - + String.format(" flags=0x%08x", fl) - + " pf=" + pf.toShortString() + " df=" + df.toShortString()); + + " flags=" + ViewDebug.flagsToString(LayoutParams.class, "flags", fl) + + " pf=" + pf.toShortString() + " df=" + df.toShortString() + + " f=" + f.toShortString()); if (!sTmpLastParentFrame.equals(pf)) { windowFrames.setContentChanged(true); } - win.computeFrameAndUpdateSourceFrame(displayFrames); + if (!windowFrames.mIsSimulatingDecorWindow) { + win.setFrame(); + } } WindowState getTopFullscreenOpaqueWindow() { diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 96c935af9d5a..63246aca2587 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -392,7 +392,7 @@ class TaskSnapshotController { final WindowState imeWindow = task.getDisplayContent().mInputMethodWindow; SurfaceControl.ScreenshotHardwareBuffer imeBuffer = null; if (imeWindow != null && imeWindow.isWinVisibleLw()) { - final Rect bounds = imeWindow.getContainingFrame(); + final Rect bounds = imeWindow.getParentFrame(); bounds.offsetTo(0, 0); imeBuffer = SurfaceControl.captureLayersExcluding(imeWindow.getSurfaceControl(), bounds, 1.0f, pixelFormat, null); diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java index baea85439582..c3d3c8225055 100644 --- a/services/core/java/com/android/server/wm/WindowFrames.java +++ b/services/core/java/com/android/server/wm/WindowFrames.java @@ -17,7 +17,6 @@ package com.android.server.wm; import static com.android.server.wm.WindowFramesProto.COMPAT_FRAME; -import static com.android.server.wm.WindowFramesProto.CONTAINING_FRAME; import static com.android.server.wm.WindowFramesProto.DISPLAY_FRAME; import static com.android.server.wm.WindowFramesProto.FRAME; import static com.android.server.wm.WindowFramesProto.PARENT_FRAME; @@ -37,32 +36,16 @@ public class WindowFrames { private static final StringBuilder sTmpSB = new StringBuilder(); /** - * In most cases, this is the area of the entire screen. - * - * TODO(b/111611553): The name is unclear and most likely should be swapped with - * {@link #mDisplayFrame} - * TODO(b/111611553): In some cases, it also includes top insets, like for IME. Determine - * whether this is still necessary to do. + * The frame to be referenced while applying gravity and MATCH_PARENT. */ public final Rect mParentFrame = new Rect(); /** - * The entire screen area of the {@link Task} this window is in. Usually equal to the - * screen area of the device. - * - * TODO(b/111611553): The name is unclear and most likely should be swapped with - * {@link #mParentFrame} + * The bounds that the window should fit. */ public final Rect mDisplayFrame = new Rect(); /** - * Similar to {@link #mDisplayFrame} - * - * TODO: Why is this different than mDisplayFrame - */ - final Rect mContainingFrame = new Rect(); - - /** * "Real" frame that the application sees, in display coordinate space. */ final Rect mFrame = new Rect(); @@ -124,10 +107,6 @@ public class WindowFrames { return (mLastFrame.width() != mFrame.width()) || (mLastFrame.height() != mFrame.height()); } - void offsetFrames(int layoutXDiff, int layoutYDiff) { - mFrame.offset(layoutXDiff, layoutYDiff); - } - /** * Updates info about whether the size of the window has changed since last reported. * @@ -188,16 +167,13 @@ public class WindowFrames { final long token = proto.start(fieldId); mParentFrame.dumpDebug(proto, PARENT_FRAME); mDisplayFrame.dumpDebug(proto, DISPLAY_FRAME); - mContainingFrame.dumpDebug(proto, CONTAINING_FRAME); mFrame.dumpDebug(proto, FRAME); mCompatFrame.dumpDebug(proto, COMPAT_FRAME); proto.end(token); } public void dump(PrintWriter pw, String prefix) { - pw.println(prefix + "Frames: containing=" - + mContainingFrame.toShortString(sTmpSB) - + " parent=" + mParentFrame.toShortString(sTmpSB) + pw.println(prefix + "Frames: parent=" + mParentFrame.toShortString(sTmpSB) + " display=" + mDisplayFrame.toShortString(sTmpSB)); pw.println(prefix + "mFrame=" + mFrame.toShortString(sTmpSB) + " last=" + mLastFrame.toShortString(sTmpSB)); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index c4a518395eea..5d916eaa4bf7 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1783,6 +1783,7 @@ public class WindowManagerService extends IWindowManager.Stub win.mToken.addWindow(win); displayPolicy.addWindowLw(win, attrs); + displayPolicy.setDropInputModePolicy(win, win.mAttrs); if (type == TYPE_APPLICATION_STARTING && activity != null) { activity.attachStartingWindow(win); ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "addWindow: %s startingWindow=%s", diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index a5f812f15ad5..65389f0385d5 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -38,10 +38,9 @@ import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_ import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE; -import static android.view.WindowInsets.Type.displayCutout; -import static android.view.WindowInsets.Type.ime; import static android.view.WindowInsets.Type.systemBars; import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; +import static android.view.WindowLayout.UNSPECIFIED_LENGTH; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON; @@ -49,7 +48,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_BLUR_BEHIND; import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND; import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; -import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; import static android.view.WindowManager.LayoutParams.FLAG_SCALED; @@ -224,7 +222,6 @@ import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import android.view.Display; import android.view.DisplayInfo; -import android.view.Gravity; import android.view.IWindow; import android.view.IWindowFocusObserver; import android.view.IWindowId; @@ -473,9 +470,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP /** The frames used to compute a temporal layout appearance. */ private WindowFrames mSimulatedWindowFrames; - /** Usually the same as {@link #getBounds()}. */ - private final Rect mInsetFrame = new Rect(); - /** * List of rects where system gestures should be ignored. * @@ -1138,10 +1132,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mWinAnimator = new WindowStateAnimator(this); mWinAnimator.mAlpha = a.alpha; - mRequestedWidth = 0; - mRequestedHeight = 0; - mLastRequestedWidth = 0; - mLastRequestedHeight = 0; + mRequestedWidth = UNSPECIFIED_LENGTH; + mRequestedHeight = UNSPECIFIED_LENGTH; + mLastRequestedWidth = UNSPECIFIED_LENGTH; + mLastRequestedHeight = UNSPECIFIED_LENGTH; mLayer = 0; mOverrideScale = mWmService.mAtmService.mCompatModePackages.getCompatScale( mAttrs.packageName, s.mUid); @@ -1244,136 +1238,26 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return mSession.mCanAcquireSleepToken; } - /** - * Subtracts the insets calculated by intersecting {@param layoutFrame} with {@param insetFrame} - * from {@param frame}. In other words, it applies the insets that would result if - * {@param frame} would be shifted to {@param layoutFrame} and then applying the insets from - * {@param insetFrame}. Also it respects {@param displayFrame} in case window has minimum - * width/height applied and insets should be overridden. - */ - private void subtractInsets(Rect frame, Rect layoutFrame, Rect insetFrame, Rect displayFrame) { - final int left = Math.max(0, insetFrame.left - Math.max(layoutFrame.left, displayFrame.left)); - final int top = Math.max(0, insetFrame.top - Math.max(layoutFrame.top, displayFrame.top)); - final int right = Math.max(0, Math.min(layoutFrame.right, displayFrame.right) - insetFrame.right); - final int bottom = Math.max(0, Math.min(layoutFrame.bottom, displayFrame.bottom) - insetFrame.bottom); - frame.inset(left, top, right, bottom); - } - - void computeFrameAndUpdateSourceFrame(DisplayFrames displayFrames) { - computeFrame(displayFrames); - // Update the source frame to provide insets to other windows during layout. If the - // simulated frames exist, then this is not computing a stable result so just skip. - if (mControllableInsetProvider != null && mSimulatedWindowFrames == null) { - mControllableInsetProvider.updateSourceFrame(); - } - } - - /** - * Perform standard frame computation. The result can be obtained with getFrame() if so desired. - */ - void computeFrame(DisplayFrames displayFrames) { + boolean skipLayout() { if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) { // This window is being replaced and either already got information that it's being // removed or we are still waiting for some information. Because of this we don't // want to apply any more changes to it, so it remains in this state until new window // appears. - return; + return true; } - mHaveFrame = true; - - final Task task = getTask(); - final boolean isFullscreenAndFillsArea = !inMultiWindowMode() && matchesDisplayAreaBounds(); - final boolean windowsAreFloating = task != null && task.isFloating(); - final DisplayContent dc = getDisplayContent(); - final DisplayInfo displayInfo = getDisplayInfo(); - final WindowFrames windowFrames = getLayoutingWindowFrames(); - - mInsetFrame.set(getBounds()); - - // Denotes the actual frame used to calculate the insets and to perform the layout. When - // resizing in docked mode, we'd like to freeze the layout, so we also need to freeze the - // insets temporarily. By the notion of a task having a different layout frame, we can - // achieve that while still moving the task around. - final Rect layoutContainingFrame; - final Rect layoutDisplayFrame; - - // The offset from the layout containing frame to the actual containing frame. - final int layoutXDiff; - final int layoutYDiff; - final WindowState imeWin = mWmService.mRoot.getCurrentInputMethodWindow(); - final InsetsControlTarget imeTarget = dc.getImeTarget(IME_TARGET_LAYERING); - final boolean isInputMethodAdjustTarget = windowsAreFloating - ? imeTarget != null && task == imeTarget.getWindow().getTask() - : isImeLayeringTarget(); - final boolean isImeTarget = - imeWin != null && imeWin.isVisibleNow() && isInputMethodAdjustTarget; - if (isFullscreenAndFillsArea || layoutInParentFrame()) { - // We use the parent frame as the containing frame for fullscreen and child windows - windowFrames.mContainingFrame.set(windowFrames.mParentFrame); - layoutDisplayFrame = windowFrames.mDisplayFrame; - layoutContainingFrame = windowFrames.mParentFrame; - layoutXDiff = 0; - layoutYDiff = 0; - } else { - windowFrames.mContainingFrame.set(getBounds()); - // IME is up and obscuring this window. Adjust the window position so it is visible. - if (isImeTarget) { - if (inFreeformWindowingMode()) { - // Push the freeform window up to make room for the IME. However, don't push - // it up past the bottom of the top bar. - final InsetsState state = dc.getInsetsStateController().getRawInsetsState(); - final Rect visibleFrame = mTmpRect; - visibleFrame.set(state.getDisplayFrame()); - visibleFrame.inset(state.calculateInsets(visibleFrame, - systemBars() | ime() | displayCutout(), false /* ignoreVisibility */)); - final int bottomOverlap = - windowFrames.mContainingFrame.bottom - visibleFrame.bottom; - if (bottomOverlap > 0) { - final int distanceToTop = Math.max(windowFrames.mContainingFrame.top - - visibleFrame.top, 0); - int offs = Math.min(bottomOverlap, distanceToTop); - windowFrames.mContainingFrame.offset(0, -offs); - mInsetFrame.offset(0, -offs); - } - } else if (!inPinnedWindowingMode() && windowFrames.mContainingFrame.bottom - > windowFrames.mParentFrame.bottom) { - // But in docked we want to behave like fullscreen and behave as if the task - // were given smaller bounds for the purposes of layout. Skip adjustments for - // the root pinned task, they are handled separately in the - // PinnedTaskController. - windowFrames.mContainingFrame.bottom = windowFrames.mParentFrame.bottom; - } - } + // Skip layout of the window when in transition to pip mode. + return mActivityRecord != null && mActivityRecord.mWaitForEnteringPinnedMode; + } - if (windowsAreFloating) { - // In floating modes (e.g. freeform, pinned) we have only to set the rectangle - // if it wasn't set already. No need to intersect it with the (visible) - // "content frame" since it is allowed to be outside the visible desktop. - if (windowFrames.mContainingFrame.isEmpty()) { - windowFrames.mContainingFrame.set(windowFrames.mDisplayFrame); - } - } + // TODO(b/161810301): Make the frame be passed from the client side. + void setFrame() { + // TODO(b/161810301): Set the window frame here. We don't have to do it now because + // DisplayPolicy has already done it for the window. - layoutDisplayFrame = mTmpRect2; - layoutDisplayFrame.set(windowFrames.mDisplayFrame); - windowFrames.mDisplayFrame.set(windowFrames.mContainingFrame); - layoutXDiff = mInsetFrame.left - windowFrames.mContainingFrame.left; - layoutYDiff = mInsetFrame.top - windowFrames.mContainingFrame.top; - layoutContainingFrame = mInsetFrame; - mTmpRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight); - subtractInsets(windowFrames.mDisplayFrame, layoutContainingFrame, layoutDisplayFrame, - mTmpRect); - if (!layoutInParentFrame()) { - subtractInsets(windowFrames.mContainingFrame, layoutContainingFrame, - windowFrames.mParentFrame, mTmpRect); - subtractInsets(mInsetFrame, layoutContainingFrame, windowFrames.mParentFrame, - mTmpRect); - } - layoutDisplayFrame.intersect(layoutContainingFrame); - } + mHaveFrame = true; - final int pw = windowFrames.mContainingFrame.width(); - final int ph = windowFrames.mContainingFrame.height(); + final WindowFrames windowFrames = mWindowFrames; if (mRequestedWidth != mLastRequestedWidth || mRequestedHeight != mLastRequestedHeight) { mLastRequestedWidth = mRequestedWidth; @@ -1381,21 +1265,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP windowFrames.setContentChanged(true); } - final int fw = windowFrames.mFrame.width(); - final int fh = windowFrames.mFrame.height(); - - applyGravityAndUpdateFrame(windowFrames, layoutContainingFrame, layoutDisplayFrame, - displayFrames); - - if (mAttrs.type == TYPE_DOCK_DIVIDER) { - if (!windowFrames.mFrame.equals(windowFrames.mLastFrame)) { - mMovedByResize = true; - } - } - - // Offset the actual frame by the amount layout frame is off. - windowFrames.offsetFrames(-layoutXDiff, -layoutYDiff); - windowFrames.mCompatFrame.set(windowFrames.mFrame); if (hasCompatScale()) { // Also the scaled frame that we report to the app needs to be @@ -1403,14 +1272,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP windowFrames.mCompatFrame.scale(mInvGlobalScale); } - if (mIsWallpaper && (fw != windowFrames.mFrame.width() - || fh != windowFrames.mFrame.height())) { - dc.mWallpaperController.updateWallpaperOffset(this, false /* sync */); - } - // Calculate relative frame windowFrames.mRelFrame.set(windowFrames.mFrame); - WindowContainer parent = getParent(); + WindowContainer<?> parent = getParent(); int parentLeft = 0; int parentTop = 0; if (mIsChildWindow) { @@ -1425,14 +1289,39 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP windowFrames.mFrame.top - parentTop); if (DEBUG_LAYOUT || DEBUG) { + final int pw = windowFrames.mParentFrame.width(); + final int ph = windowFrames.mParentFrame.height(); Slog.v(TAG, "Resolving (mRequestedWidth=" - + mRequestedWidth + ", mRequestedheight=" - + mRequestedHeight + ") to" + " (pw=" + pw + ", ph=" + ph - + "): frame=" + windowFrames.mFrame.toShortString() - + " " + mAttrs.getTitle()); + + mRequestedWidth + ", mRequestedheight=" + + mRequestedHeight + ") to" + " (pw=" + pw + ", ph=" + ph + + "): frame=" + windowFrames.mFrame.toShortString() + + " " + mAttrs.getTitle()); + } + + if (mAttrs.type == TYPE_DOCK_DIVIDER) { + if (!windowFrames.mFrame.equals(windowFrames.mLastFrame)) { + mMovedByResize = true; + } + } + + if (mIsWallpaper) { + final Rect lastFrame = windowFrames.mLastFrame; + final Rect frame = windowFrames.mFrame; + if (lastFrame.width() != frame.width() || lastFrame.height() != frame.height()) { + mDisplayContent.mWallpaperController.updateWallpaperOffset(this, false /* sync */); + } + } + + // Update the source frame to provide insets to other windows during layout. + if (mControllableInsetProvider != null) { + mControllableInsetProvider.updateSourceFrame(); } } + // TODO(b/161810301): Remove this after INSETS_LAYOUT_GENERALIZATION is removed. + void computeFrameAndUpdateSourceFrame(DisplayFrames displayFrames) { + } + @Override public Rect getBounds() { // The window bounds are used for layout in screen coordinates. If the token has bounds for @@ -1463,10 +1352,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return mWindowFrames.mParentFrame; } - Rect getContainingFrame() { - return mWindowFrames.mContainingFrame; - } - void getCompatFrameSize(Rect outFrame) { outFrame.set(0, 0, mWindowFrames.mCompatFrame.width(), mWindowFrames.mCompatFrame.height()); } @@ -4023,11 +3908,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return getDisplayContent().mCurrentFocus == this; } - /** Is this window in a container that takes up the entire screen space? */ - private boolean inAppWindowThatMatchesParentBounds() { - return mActivityRecord == null || (mActivityRecord.matchParentBounds() && !inMultiWindowMode()); - } - /** * @return true if activity bounds are letterboxed or letterboxed for diplay cutout. * @@ -4402,98 +4282,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return mStringNameCache; } - private void applyGravityAndUpdateFrame(WindowFrames windowFrames, Rect containingFrame, - Rect displayFrame, DisplayFrames displayFrames) { - final int pw = containingFrame.width(); - final int ph = containingFrame.height(); - final Task task = getTask(); - final boolean inNonFullscreenContainer = !inAppWindowThatMatchesParentBounds(); - final WindowManager.LayoutParams attrs = getLayoutingAttrs(displayFrames.mRotation); - final boolean noLimits = (attrs.flags & FLAG_LAYOUT_NO_LIMITS) != 0; - - // We need to fit it to the display if either - // a) The window is in a fullscreen container, or we don't have a task (we assume fullscreen - // for the taskless windows) - // b) If it's a secondary app window, we also need to fit it to the display unless - // FLAG_LAYOUT_NO_LIMITS is set. This is so we place Popups, dialogs, and similar windows on - // screen, but SurfaceViews want to be always at a specific location so we don't fit it to - // the display. - final boolean fitToDisplay = (task == null || !inNonFullscreenContainer) - || ((attrs.type != TYPE_BASE_APPLICATION) && !noLimits); - float x, y; - int w,h; - - final boolean hasCompatScale = hasCompatScale(); - if ((attrs.flags & FLAG_SCALED) != 0 || mAttrs != attrs) { - // For the window with different layout attrs for different rotations, we need to avoid - // using requested size. Otherwise, when finishing a simulated rotation, the information - // coming from WindowManagerServices to the ViewRootImpl may not contain the correct - // value for the new rotation, and there will be a quick flash of wrong layout when the - // simulated activity faded out. - if (attrs.width < 0) { - w = pw; - } else if (hasCompatScale) { - w = (int) (attrs.width * mGlobalScale + .5f); - } else { - w = attrs.width; - } - if (attrs.height < 0) { - h = ph; - } else if (hasCompatScale) { - h = (int) (attrs.height * mGlobalScale + .5f); - } else { - h = attrs.height; - } - } else { - if (attrs.width == MATCH_PARENT) { - w = pw; - } else if (hasCompatScale) { - w = (int) (mRequestedWidth * mGlobalScale + .5f); - } else { - w = mRequestedWidth; - } - if (attrs.height == MATCH_PARENT) { - h = ph; - } else if (hasCompatScale) { - h = (int) (mRequestedHeight * mGlobalScale + .5f); - } else { - h = mRequestedHeight; - } - } - - if (hasCompatScale) { - x = attrs.x * mGlobalScale; - y = attrs.y * mGlobalScale; - } else { - x = attrs.x; - y = attrs.y; - } - - if (inNonFullscreenContainer && !layoutInParentFrame()) { - // Make sure window fits in containing frame since it is in a non-fullscreen task as - // required by {@link Gravity#apply} call. - w = Math.min(w, pw); - h = Math.min(h, ph); - } - - // Set mFrame - Gravity.apply(attrs.gravity, w, h, containingFrame, - (int) (x + attrs.horizontalMargin * pw), - (int) (y + attrs.verticalMargin * ph), windowFrames.mFrame); - // Now make sure the window fits in the overall display frame. - if (fitToDisplay) { - Gravity.applyDisplay(attrs.gravity, displayFrame, windowFrames.mFrame); - } - - // We need to make sure we update the CompatFrame as it is used for - // cropping decisions, etc, on systems where we lack a decor layer. - windowFrames.mCompatFrame.set(windowFrames.mFrame); - if (hasCompatScale) { - // See comparable block in computeFrameLw. - windowFrames.mCompatFrame.scale(mInvGlobalScale); - } - } - boolean isChildWindow() { return mIsChildWindow; } @@ -5884,7 +5672,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // animation target (which will be different than the task bounds) outFrame.set(getTask().getParent().getBounds()); } else { - outFrame.set(getContainingFrame()); + outFrame.set(getParentFrame()); } outSurfaceInsets.set(getAttrs().surfaceInsets); final InsetsState state = getInsetsStateWithVisibilityOverride(); diff --git a/services/tests/PackageManager/TEST_MAPPING b/services/tests/PackageManager/TEST_MAPPING new file mode 100644 index 000000000000..72d4c828c452 --- /dev/null +++ b/services/tests/PackageManager/TEST_MAPPING @@ -0,0 +1,8 @@ +{ + "presubmit": [ + { + "name": "PackageInstallerTests" + } + ] +} + diff --git a/services/tests/PackageManagerComponentOverrideTests/TEST_MAPPING b/services/tests/PackageManagerComponentOverrideTests/TEST_MAPPING new file mode 100644 index 000000000000..528c949f36de --- /dev/null +++ b/services/tests/PackageManagerComponentOverrideTests/TEST_MAPPING @@ -0,0 +1,8 @@ +{ + "presubmit": [ + { + "name": "PackageManagerComponentOverrideTests" + } + ] +} + diff --git a/services/tests/PackageManagerServiceTests/OWNERS b/services/tests/PackageManagerServiceTests/OWNERS index 182dfe8fca9e..86ae5818e91c 100644 --- a/services/tests/PackageManagerServiceTests/OWNERS +++ b/services/tests/PackageManagerServiceTests/OWNERS @@ -1,3 +1 @@ -chiuwinson@google.com -patb@google.com -toddke@google.com +include /PACKAGE_MANAGER_OWNERS diff --git a/services/tests/PackageManagerServiceTests/TEST_MAPPING b/services/tests/PackageManagerServiceTests/TEST_MAPPING new file mode 100644 index 000000000000..af0008c29aaf --- /dev/null +++ b/services/tests/PackageManagerServiceTests/TEST_MAPPING @@ -0,0 +1,18 @@ +{ + "presubmit": [ + { + "name": "AppEnumerationInternalTests" + } + ], + "postsubmit": [ + { + "name": "PackageManagerServiceHostTests" + } + ], + "imports": [ + { + "path": "frameworks/base/services/tests/PackageManagerServiceTests/unit" + } + ] +} + diff --git a/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java b/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java index cb12ba7d7679..a2ecbc30ec64 100644 --- a/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java @@ -47,7 +47,6 @@ public class BatteryServiceTest extends AndroidTestCase { @Mock BatteryService.HealthServiceWrapper.IHealthSupplier mHealthServiceSupplier; BatteryService.HealthServiceWrapper mWrapper; - private static final String HEALTHD = BatteryService.HealthServiceWrapper.INSTANCE_HEALTHD; private static final String VENDOR = BatteryService.HealthServiceWrapper.INSTANCE_VENDOR; @Override @@ -117,7 +116,7 @@ public class BatteryServiceTest extends AndroidTestCase { @SmallTest public void testWrapPreferVendor() throws Exception { - initForInstances(VENDOR, HEALTHD); + initForInstances(VENDOR); mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier); waitHandlerThreadFinish(); verify(mCallback, times(1)).onRegistration(same(null), same(mMockedHal), eq(VENDOR)); @@ -126,16 +125,6 @@ public class BatteryServiceTest extends AndroidTestCase { } @SmallTest - public void testUseHealthd() throws Exception { - initForInstances(HEALTHD); - mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier); - waitHandlerThreadFinish(); - verify(mCallback, times(1)).onRegistration(same(null), same(mMockedHal), eq(HEALTHD)); - verify(mCallback, never()).onRegistration(same(mMockedHal), same(mMockedHal), anyString()); - verify(mCallback, times(1)).onRegistration(same(mMockedHal), same(mMockedHal2), eq(HEALTHD)); - } - - @SmallTest public void testNoService() throws Exception { initForInstances("unrelated"); try { diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java index fb5c557c8d4b..96af61737bff 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java @@ -100,7 +100,11 @@ public class FullScreenMagnificationControllerTest { MagnificationAnimationCallback.class); private final MagnificationInfoChangedCallback mRequestObserver = mock( MagnificationInfoChangedCallback.class); - final MessageCapturingHandler mMessageCapturingHandler = new MessageCapturingHandler(null); + private final MessageCapturingHandler mMessageCapturingHandler = new MessageCapturingHandler( + null); + private final MagnificationScaleProvider mScaleProvider = mock( + MagnificationScaleProvider.class); + ValueAnimator mMockValueAnimator; ValueAnimator.AnimatorUpdateListener mTargetAnimationListener; @@ -123,7 +127,7 @@ public class FullScreenMagnificationControllerTest { initMockWindowManager(); mFullScreenMagnificationController = new FullScreenMagnificationController( - mMockControllerCtx, new Object(), mRequestObserver); + mMockControllerCtx, new Object(), mRequestObserver, mScaleProvider); } @After @@ -412,12 +416,12 @@ public class FullScreenMagnificationControllerTest { MagnificationSpec startSpec = getCurrentMagnificationSpec(displayId); PointF newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER; PointF offsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, - FullScreenMagnificationController.MAX_SCALE); + MagnificationScaleProvider.MAX_SCALE); MagnificationSpec endSpec = getMagnificationSpec( - FullScreenMagnificationController.MAX_SCALE, offsets); + MagnificationScaleProvider.MAX_SCALE, offsets); assertTrue(mFullScreenMagnificationController.setScaleAndCenter(displayId, - FullScreenMagnificationController.MAX_SCALE + 1.0f, + MagnificationScaleProvider.MAX_SCALE + 1.0f, newCenter.x, newCenter.y, false, SERVICE_ID_1)); mMessageCapturingHandler.sendAllMessages(); @@ -632,31 +636,6 @@ public class FullScreenMagnificationControllerTest { } @Test - public void testSetUserId_resetsOnlyIfIdChanges() { - for (int i = 0; i < DISPLAY_COUNT; i++) { - testSetUserId_resetsOnlyIfIdChanges(i); - resetMockWindowManager(); - } - } - - private void testSetUserId_resetsOnlyIfIdChanges(int displayId) { - final int userId1 = 1; - final int userId2 = 2; - - register(displayId); - mFullScreenMagnificationController.setUserId(userId1); - PointF startCenter = INITIAL_MAGNIFICATION_BOUNDS_CENTER; - float scale = 2.0f; - mFullScreenMagnificationController.setScale(displayId, scale, startCenter.x, startCenter.y, - false, SERVICE_ID_1); - - mFullScreenMagnificationController.setUserId(userId1); - assertTrue(mFullScreenMagnificationController.isMagnifying(displayId)); - mFullScreenMagnificationController.setUserId(userId2); - assertFalse(mFullScreenMagnificationController.isMagnifying(displayId)); - } - - @Test public void testResetIfNeeded_doesWhatItSays() { for (int i = 0; i < DISPLAY_COUNT; i++) { testResetIfNeeded_doesWhatItSays(i); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java index 6c32f7e8bacb..2060223f6f98 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java @@ -22,6 +22,8 @@ import static android.view.MotionEvent.ACTION_POINTER_DOWN; import static android.view.MotionEvent.ACTION_POINTER_UP; import static android.view.MotionEvent.ACTION_UP; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + import static com.android.server.testutils.TestUtils.strictMock; import static org.junit.Assert.assertFalse; @@ -38,16 +40,15 @@ import static org.mockito.Mockito.when; import android.animation.ValueAnimator; import android.annotation.NonNull; -import android.content.Context; import android.graphics.PointF; import android.os.Handler; import android.os.Message; +import android.testing.TestableContext; import android.util.DebugUtils; import android.view.InputDevice; import android.view.MotionEvent; import android.view.ViewConfiguration; -import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import com.android.server.accessibility.AccessibilityManagerService; @@ -60,6 +61,7 @@ import com.android.server.wm.WindowManagerInternal; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -121,7 +123,6 @@ public class FullScreenMagnificationGestureHandlerTest { private static final int DISPLAY_0 = 0; - private Context mContext; FullScreenMagnificationController mFullScreenMagnificationController; @Mock MagnificationGestureHandler.Callback mMockCallback; @@ -134,6 +135,9 @@ public class FullScreenMagnificationGestureHandlerTest { @Mock AccessibilityTraceManager mMockTraceManager; + @Rule + public final TestableContext mContext = new TestableContext(getInstrumentation().getContext()); + private OffsettableClock mClock; private FullScreenMagnificationGestureHandler mMgh; private TestHandler mHandler; @@ -143,7 +147,6 @@ public class FullScreenMagnificationGestureHandlerTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - mContext = InstrumentationRegistry.getContext(); final FullScreenMagnificationController.ControllerContext mockController = mock(FullScreenMagnificationController.ControllerContext.class); final WindowManagerInternal mockWindowManager = mock(WindowManagerInternal.class); @@ -157,14 +160,16 @@ public class FullScreenMagnificationGestureHandlerTest { when(mockController.getAnimationDuration()).thenReturn(1000L); when(mockWindowManager.setMagnificationCallbacks(eq(DISPLAY_0), any())).thenReturn(true); mFullScreenMagnificationController = new FullScreenMagnificationController(mockController, - new Object(), mMagnificationInfoChangedCallback) { + new Object(), mMagnificationInfoChangedCallback, + new MagnificationScaleProvider(mContext)) { @Override public boolean magnificationRegionContains(int displayId, float x, float y) { return true; } @Override - void setForceShowMagnifiableBounds(int displayId, boolean show) {} + void setForceShowMagnifiableBounds(int displayId, boolean show) { + } }; mFullScreenMagnificationController.register(DISPLAY_0); mClock = new OffsettableClock.Stopped(); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java index 2cb3d27229bc..69061c14c70e 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java @@ -46,6 +46,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.provider.Settings; import android.test.mock.MockContentResolver; +import android.testing.DexmakerShareClassLoaderRule; import android.view.Display; import android.view.accessibility.IRemoteMagnificationAnimationCallback; import android.view.accessibility.MagnificationAnimationCallback; @@ -58,6 +59,7 @@ import com.android.server.accessibility.AccessibilityTraceManager; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -79,7 +81,8 @@ public class MagnificationControllerTest { private static final float MAGNIFIED_CENTER_X = 100; private static final float MAGNIFIED_CENTER_Y = 200; private static final float DEFAULT_SCALE = 3f; - private static final int CURRENT_USER_ID = UserHandle.USER_CURRENT; + private static final int CURRENT_USER_ID = UserHandle.USER_SYSTEM; + private static final int SECOND_USER_ID = CURRENT_USER_ID + 1; private static final int MODE_WINDOW = Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW; private static final int MODE_FULLSCREEN = Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; @@ -94,6 +97,7 @@ public class MagnificationControllerTest { private Context mContext; @Mock private FullScreenMagnificationController mScreenMagnificationController; + private MagnificationScaleProvider mScaleProvider; @Captor private ArgumentCaptor<MagnificationAnimationCallback> mCallbackArgumentCaptor; @@ -103,6 +107,11 @@ public class MagnificationControllerTest { private MagnificationController mMagnificationController; private FullScreenMagnificationControllerStubber mScreenMagnificationControllerStubber; + // To mock package-private class + @Rule + public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = + new DexmakerShareClassLoaderRule(); + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); @@ -113,15 +122,17 @@ public class MagnificationControllerTest { Settings.Secure.putFloatForUser(mMockResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, DEFAULT_SCALE, CURRENT_USER_ID); + mScaleProvider = spy(new MagnificationScaleProvider(mContext)); mWindowMagnificationManager = Mockito.spy( new WindowMagnificationManager(mContext, CURRENT_USER_ID, - mock(WindowMagnificationManager.Callback.class), mTraceManager)); + mock(WindowMagnificationManager.Callback.class), mTraceManager, + mScaleProvider)); mMockConnection = new MockWindowMagnificationConnection(true); mWindowMagnificationManager.setConnection(mMockConnection.getConnection()); mScreenMagnificationControllerStubber = new FullScreenMagnificationControllerStubber( mScreenMagnificationController); mMagnificationController = spy(new MagnificationController(mService, new Object(), mContext, - mScreenMagnificationController, mWindowMagnificationManager)); + mScreenMagnificationController, mWindowMagnificationManager, mScaleProvider)); mMagnificationController.setMagnificationCapabilities( Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL); @@ -283,14 +294,16 @@ public class MagnificationControllerTest { verify(mScreenMagnificationController).onDisplayRemoved(TEST_DISPLAY); verify(mWindowMagnificationManager).onDisplayRemoved(TEST_DISPLAY); + verify(mScaleProvider).onDisplayRemoved(TEST_DISPLAY); } @Test - public void updateUserIdIfNeeded_AllModulesAvailable_setUserId() { - mMagnificationController.updateUserIdIfNeeded(CURRENT_USER_ID); + public void updateUserIdIfNeeded_AllModulesAvailable_disableMagnificationAndChangeUserId() { + mMagnificationController.updateUserIdIfNeeded(SECOND_USER_ID); - verify(mScreenMagnificationController).setUserId(CURRENT_USER_ID); - verify(mWindowMagnificationManager).setUserId(CURRENT_USER_ID); + verify(mScreenMagnificationController).resetAllIfNeeded(false); + verify(mWindowMagnificationManager).disableAllWindowMagnifiers(); + verify(mScaleProvider).onUserChanged(SECOND_USER_ID); } @Test @@ -575,6 +588,13 @@ public class MagnificationControllerTest { verify(mMagnificationController, never()).logMagnificationModeWithIme(anyInt()); } + @Test + public void onUserRemoved_notifyScaleProvider() { + mMagnificationController.onUserRemoved(SECOND_USER_ID); + + verify(mScaleProvider).onUserRemoved(SECOND_USER_ID); + } + private void setMagnificationEnabled(int mode) throws RemoteException { setMagnificationEnabled(mode, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y); } @@ -627,7 +647,8 @@ public class MagnificationControllerTest { TEST_DISPLAY); doAnswer(invocation -> mIsMagnifying).when( mScreenMagnificationController).isForceShowMagnifiableBounds(TEST_DISPLAY); - doAnswer(invocation -> mScale).when(mScreenMagnificationController).getPersistedScale(); + doAnswer(invocation -> mScale).when(mScreenMagnificationController).getPersistedScale( + TEST_DISPLAY); doAnswer(invocation -> mScale).when(mScreenMagnificationController).getScale( TEST_DISPLAY); doAnswer(invocation -> mCenterX).when(mScreenMagnificationController).getCenterX( diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationScaleProviderTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationScaleProviderTest.java new file mode 100644 index 000000000000..9b392b200821 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationScaleProviderTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.accessibility.magnification; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static org.junit.Assert.assertEquals; + +import android.os.UserHandle; +import android.testing.TestableContext; +import android.view.Display; + +import com.android.compatibility.common.util.TestUtils; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +/** + * Tests for {@link MagnificationScaleProvider}. + */ +public class MagnificationScaleProviderTest { + + private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY + 1; + private static final int CURRENT_USER_ID = UserHandle.USER_SYSTEM; + private static final int SECOND_USER_ID = CURRENT_USER_ID + 1; + + private static final float TEST_SCALE = 3; + private static final float DEFAULT_SCALE = + MagnificationScaleProvider.DEFAULT_MAGNIFICATION_SCALE; + + @Rule + public final TestableContext mContext = new TestableContext(getInstrumentation().getContext()); + + private MagnificationScaleProvider mScaleProvider; + + @Before + public void setUp() { + mScaleProvider = new MagnificationScaleProvider(mContext); + } + + @Test + public void putScaleOnDefaultDisplay_getExpectedValue() throws Exception { + mScaleProvider.putScale(TEST_SCALE, Display.DEFAULT_DISPLAY); + + TestUtils.waitUntil("settings value is not changed", + () -> Float.compare(mScaleProvider.getScale(Display.DEFAULT_DISPLAY), + TEST_SCALE) == 0); + } + + @Test + public void putScaleOnTestDisplay_getExpectedValue() { + mScaleProvider.putScale(TEST_SCALE, TEST_DISPLAY); + + assertEquals(TEST_SCALE, mScaleProvider.getScale(TEST_DISPLAY), 0); + } + + @Test + public void onUserChanged_putScale_fallbackToDefaultScale() { + mScaleProvider.putScale(TEST_SCALE, TEST_DISPLAY); + + mScaleProvider.onUserChanged(SECOND_USER_ID); + assertEquals(DEFAULT_SCALE, mScaleProvider.getScale(TEST_DISPLAY), 0); + } + + @Test + public void onUserRemoved_setScaleOnSecondUser_fallbackToDefaultScale() { + mScaleProvider.onUserChanged(SECOND_USER_ID); + mScaleProvider.putScale(TEST_SCALE, TEST_DISPLAY); + mScaleProvider.onUserChanged(CURRENT_USER_ID); + + mScaleProvider.onUserRemoved(SECOND_USER_ID); + // Assume the second user is created with the same id + mScaleProvider.onUserChanged(SECOND_USER_ID); + + assertEquals(DEFAULT_SCALE, mScaleProvider.getScale(TEST_DISPLAY), 0); + } + + @Test + public void onTestDisplayRemoved_setScaleOnTestDisplay_fallbackToDefaultScale() { + mScaleProvider.putScale(TEST_SCALE, TEST_DISPLAY); + + mScaleProvider.onDisplayRemoved(TEST_DISPLAY); + + assertEquals(DEFAULT_SCALE, mScaleProvider.getScale(TEST_DISPLAY), 0); + } +} diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java index 95f43275376e..1b8aff50d2e2 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java @@ -21,10 +21,10 @@ import static com.android.server.testutils.TestUtils.strictMock; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; -import android.content.Context; import android.graphics.PointF; import android.graphics.Rect; import android.os.RemoteException; +import android.testing.TestableContext; import android.util.DebugUtils; import android.view.InputDevice; import android.view.MotionEvent; @@ -39,6 +39,7 @@ import com.android.server.accessibility.utils.TouchEventGenerator; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -67,7 +68,10 @@ public class WindowMagnificationGestureHandlerTest { public static final float DEFAULT_TAP_Y = 299; private static final int DISPLAY_0 = MockWindowMagnificationConnection.TEST_DISPLAY; - private Context mContext; + @Rule + public final TestableContext mContext = new TestableContext( + InstrumentationRegistry.getInstrumentation().getContext()); + private WindowMagnificationManager mWindowMagnificationManager; private MockWindowMagnificationConnection mMockConnection; private WindowMagnificationGestureHandler mWindowMagnificationGestureHandler; @@ -79,9 +83,9 @@ public class WindowMagnificationGestureHandlerTest { @Before public void setUp() throws RemoteException { MockitoAnnotations.initMocks(this); - mContext = InstrumentationRegistry.getInstrumentation().getContext(); mWindowMagnificationManager = new WindowMagnificationManager(mContext, 0, - mock(WindowMagnificationManager.Callback.class), mMockTrace); + mock(WindowMagnificationManager.Callback.class), mMockTrace, + new MagnificationScaleProvider(mContext)); mMockConnection = new MockWindowMagnificationConnection(); mWindowMagnificationGestureHandler = new WindowMagnificationGestureHandler( mContext, mWindowMagnificationManager, mMockTrace, mMockCallback, diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java index af6d40f2fdf2..da881c4e6494 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java @@ -67,7 +67,7 @@ import org.mockito.invocation.InvocationOnMock; public class WindowMagnificationManagerTest { private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY; - private static final int CURRENT_USER_ID = UserHandle.USER_CURRENT; + private static final int CURRENT_USER_ID = UserHandle.USER_SYSTEM; private MockWindowMagnificationConnection mMockConnection; @Mock @@ -91,7 +91,7 @@ public class WindowMagnificationManagerTest { mResolver = new MockContentResolver(); mMockConnection = new MockWindowMagnificationConnection(); mWindowMagnificationManager = new WindowMagnificationManager(mContext, CURRENT_USER_ID, - mMockCallback, mMockTrace); + mMockCallback, mMockTrace, new MagnificationScaleProvider(mContext)); when(mContext.getContentResolver()).thenReturn(mResolver); doAnswer((InvocationOnMock invocation) -> { @@ -230,7 +230,7 @@ public class WindowMagnificationManagerTest { public void getPersistedScale() { mWindowMagnificationManager.setConnection(mMockConnection.getConnection()); - assertEquals(mWindowMagnificationManager.getPersistedScale(), 2.5f); + assertEquals(mWindowMagnificationManager.getPersistedScale(TEST_DISPLAY), 2.5f); } @Test @@ -264,7 +264,7 @@ public class WindowMagnificationManagerTest { mWindowMagnificationManager.setScale(TEST_DISPLAY, 10.0f); assertEquals(mWindowMagnificationManager.getScale(TEST_DISPLAY), - WindowMagnificationManager.MAX_SCALE); + MagnificationScaleProvider.MAX_SCALE); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java index 4957ab96ace1..03132c428077 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java @@ -50,7 +50,6 @@ import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertThat; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.spy; @@ -107,9 +106,6 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { @Before public void setUp() throws Exception { mWindow = spy(createWindow(null, TYPE_APPLICATION, "window")); - // We only test window frames set by DisplayPolicy, so here prevents computeFrameLw from - // changing those frames. - doNothing().when(mWindow).computeFrame(any()); spyOn(mStatusBarWindow); spyOn(mNavBarWindow); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java deleted file mode 100644 index 316309c8440e..000000000000 --- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.wm; - -import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; -import static android.view.InsetsState.ITYPE_IME; -import static android.view.InsetsState.ITYPE_STATUS_BAR; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; - -import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; - -import static org.junit.Assert.assertEquals; - -import android.content.res.Configuration; -import android.graphics.Rect; -import android.platform.test.annotations.Presubmit; -import android.view.DisplayInfo; -import android.view.Gravity; -import android.view.InsetsSource; -import android.view.InsetsState; -import android.view.InsetsVisibilities; -import android.view.WindowManager; - -import androidx.test.filters.FlakyTest; -import androidx.test.filters.SmallTest; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mockito; - -/** - * Tests for the {@link WindowState#computeFrameLw} method and other window frame machinery. - * - * Build/Install/Run: - * atest WmTests:WindowFrameTests - */ -@SmallTest -@Presubmit -@RunWith(WindowTestRunner.class) -public class WindowFrameTests extends WindowTestsBase { - - private DisplayContent mTestDisplayContent; - private DisplayFrames mTestDisplayFrames; - - @Before - public void setUp() throws Exception { - DisplayInfo testDisplayInfo = new DisplayInfo(mDisplayInfo); - testDisplayInfo.displayCutout = null; - mTestDisplayContent = createNewDisplay(testDisplayInfo); - mTestDisplayFrames = mTestDisplayContent.mDisplayFrames; - } - - // Do not use this function directly in the tests below. Instead, use more explicit function - // such as assertFlame(). - private void assertRect(Rect rect, int left, int top, int right, int bottom) { - assertEquals(left, rect.left); - assertEquals(top, rect.top); - assertEquals(right, rect.right); - assertEquals(bottom, rect.bottom); - } - - private void assertFrame(WindowState w, Rect frame) { - assertEquals(w.getFrame(), frame); - } - - private void assertFrame(WindowState w, int left, int top, int right, int bottom) { - assertRect(w.getFrame(), left, top, right, bottom); - } - - private void assertRelFrame(WindowState w, int left, int top, int right, int bottom) { - assertRect(w.getRelativeFrame(), left, top, right, bottom); - } - - @Test - public void testLayoutInFullscreenTask() { - // fullscreen task doesn't use bounds for computeFrame - WindowState w = createWindow(); - w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; - - // With no insets or system decor all the frames incoming from PhoneWindowManager - // are identical. - final Rect pf = new Rect(0, 0, 1000, 1000); - - // Here the window has FILL_PARENT, FILL_PARENT - // so we expect it to fill the entire available frame. - w.getWindowFrames().setFrames(pf, pf); - w.computeFrame(mTestDisplayFrames); - assertFrame(w, 0, 0, 1000, 1000); - assertRelFrame(w, 0, 0, 1000, 1000); - - // It can select various widths and heights within the bounds. - // Strangely the window attribute width is ignored for normal windows - // and we use mRequestedWidth/mRequestedHeight - w.mAttrs.width = 300; - w.mAttrs.height = 300; - w.computeFrame(mTestDisplayFrames); - // Explicit width and height without requested width/height - // gets us nothing. - assertFrame(w, 0, 0, 0, 0); - - w.mRequestedWidth = 300; - w.mRequestedHeight = 300; - w.computeFrame(mTestDisplayFrames); - // With requestedWidth/Height we can freely choose our size within the - // parent bounds. - assertFrame(w, 0, 0, 300, 300); - - // With FLAG_SCALED though, requestedWidth/height is used to control - // the unscaled surface size, and mAttrs.width/height becomes the - // layout controller. - w.mAttrs.flags = WindowManager.LayoutParams.FLAG_SCALED; - w.mRequestedHeight = -1; - w.mRequestedWidth = -1; - w.mAttrs.width = 100; - w.mAttrs.height = 100; - w.computeFrame(mTestDisplayFrames); - assertFrame(w, 0, 0, 100, 100); - w.mAttrs.flags = 0; - - // But sizes too large will be clipped to the containing frame - w.mRequestedWidth = 1200; - w.mRequestedHeight = 1200; - w.computeFrame(mTestDisplayFrames); - assertFrame(w, 0, 0, 1000, 1000); - - // Before they are clipped though windows will be shifted - w.mAttrs.x = 300; - w.mAttrs.y = 300; - w.mRequestedWidth = 1000; - w.mRequestedHeight = 1000; - w.computeFrame(mTestDisplayFrames); - assertFrame(w, 0, 0, 1000, 1000); - - // If there is room to move around in the parent frame the window will be shifted according - // to gravity. - w.mAttrs.x = 0; - w.mAttrs.y = 0; - w.mRequestedWidth = 300; - w.mRequestedHeight = 300; - w.mAttrs.gravity = Gravity.RIGHT | Gravity.TOP; - w.computeFrame(mTestDisplayFrames); - assertFrame(w, 700, 0, 1000, 300); - assertRelFrame(w, 700, 0, 1000, 300); - w.mAttrs.gravity = Gravity.RIGHT | Gravity.BOTTOM; - w.computeFrame(mTestDisplayFrames); - assertFrame(w, 700, 700, 1000, 1000); - assertRelFrame(w, 700, 700, 1000, 1000); - // Window specified x and y are interpreted as offsets in the opposite - // direction of gravity - w.mAttrs.x = 100; - w.mAttrs.y = 100; - w.computeFrame(mTestDisplayFrames); - assertFrame(w, 600, 600, 900, 900); - assertRelFrame(w, 600, 600, 900, 900); - } - - @Test - public void testLayoutNonfullscreenTask() { - removeGlobalMinSizeRestriction(); - final DisplayInfo displayInfo = mWm.getDefaultDisplayContentLocked().getDisplayInfo(); - final int logicalWidth = displayInfo.logicalWidth; - final int logicalHeight = displayInfo.logicalHeight; - - final Rect taskBounds = new Rect( - logicalWidth / 4, logicalHeight / 4, logicalWidth / 4 * 3, logicalHeight / 4 * 3); - WindowState w = createWindow(); - final Task task = w.getTask(); - // Use split-screen because it is non-fullscreen, but also not floating - task.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); - task.setBounds(taskBounds); - // The bounds we are requesting might be different from what the system resolved based on - // other factors. - final Rect resolvedTaskBounds = task.getBounds(); - w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; - - final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight); - final WindowFrames windowFrames = w.getWindowFrames(); - windowFrames.setFrames(pf, pf); - w.computeFrame(mTestDisplayFrames); - // For non fullscreen tasks the containing frame is based off the - // task bounds not the parent frame. - assertEquals(resolvedTaskBounds, w.getFrame()); - assertEquals(0, w.getRelativeFrame().left); - assertEquals(0, w.getRelativeFrame().top); - - pf.set(0, 0, logicalWidth, logicalHeight); - // We still produce insets against the containing frame the same way. - final int cfRight = logicalWidth / 2; - final int cfBottom = logicalHeight / 2; - final Rect cf = new Rect(0, 0, cfRight, cfBottom); - windowFrames.setFrames(pf, pf); - w.computeFrame(mTestDisplayFrames); - assertEquals(resolvedTaskBounds, w.getFrame()); - assertEquals(0, w.getRelativeFrame().left); - assertEquals(0, w.getRelativeFrame().top); - } - - @Test - @FlakyTest(bugId = 137879065) - public void testLayoutLetterboxedWindow() { - // First verify task behavior in multi-window mode. - final DisplayInfo displayInfo = mTestDisplayContent.getDisplayInfo(); - final int logicalWidth = displayInfo.logicalWidth; - final int logicalHeight = displayInfo.logicalHeight; - - final int taskLeft = logicalWidth / 5; - final int taskTop = logicalHeight / 5; - final int taskRight = logicalWidth / 4 * 3; - final int taskBottom = logicalHeight / 4 * 3; - final Rect taskBounds = new Rect(taskLeft, taskTop, taskRight, taskBottom); - WindowState w = createWindow(); - final Task task = w.getTask(); - // Use split-screen because it is non-fullscreen, but also not floating - task.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); - task.setBounds(taskBounds); - w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; - - final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight); - final WindowFrames windowFrames = w.getWindowFrames(); - windowFrames.setFrames(pf, pf); - w.computeFrame(mTestDisplayFrames); - // For non fullscreen tasks the containing frame is based off the - // task bounds not the parent frame. - assertFrame(w, taskLeft, taskTop, taskRight, taskBottom); - - // Now simulate switch to fullscreen for letterboxed app. - final int xInset = logicalWidth / 10; - final Rect cf = new Rect(xInset, 0, logicalWidth - xInset, logicalHeight); - Configuration config = new Configuration(w.mActivityRecord.getRequestedOverrideConfiguration()); - config.windowConfiguration.setBounds(cf); - config.windowConfiguration.setAppBounds(cf); - w.mActivityRecord.onRequestedOverrideConfigurationChanged(config); - pf.set(0, 0, logicalWidth, logicalHeight); - task.setWindowingMode(WINDOWING_MODE_FULLSCREEN); - task.setBounds(null); - windowFrames.setFrames(pf, pf); - w.computeFrame(mTestDisplayFrames); - assertFrame(w, cf); - } - - @Test - public void testFreeformContentInsets() { - removeGlobalMinSizeRestriction(); - // fullscreen task doesn't use bounds for computeFrame - WindowState w = createWindow(); - final Task task = w.getTask(); - w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; - task.setWindowingMode(WINDOWING_MODE_FREEFORM); - - // Make IME attach to the window and can produce insets. - final DisplayContent dc = mTestDisplayContent; - dc.setImeLayeringTarget(w); - WindowState mockIme = mock(WindowState.class); - Mockito.doReturn(true).when(mockIme).isVisibleNow(); - dc.mInputMethodWindow = mockIme; - final InsetsState state = dc.getInsetsStateController().getRawInsetsState(); - final InsetsSource imeSource = state.getSource(ITYPE_IME); - final Rect imeFrame = new Rect(state.getDisplayFrame()); - imeFrame.top = 400; - imeSource.setFrame(imeFrame); - imeSource.setVisible(true); - final InsetsVisibilities requestedVisibilities = new InsetsVisibilities(); - requestedVisibilities.setVisibility(ITYPE_IME, true); - w.setRequestedVisibilities(requestedVisibilities); - w.mAboveInsetsState.addSource(imeSource); - - // With no insets or system decor all the frames incoming from PhoneWindowManager - // are identical. - final Rect pf = new Rect(0, 0, 1000, 800); - - // First check that it only gets moved up enough to show window. - final Rect winRect = new Rect(200, 200, 300, 500); - task.setBounds(winRect); - w.getWindowFrames().setFrames(pf, pf); - w.computeFrame(mTestDisplayFrames); - assertFrame(w, winRect.left, imeFrame.top - winRect.height(), winRect.right, imeFrame.top); - - // Now check that it won't get moved beyond the top - winRect.bottom = 650; - task.setBounds(winRect); - w.setBounds(winRect); - w.getWindowFrames().setFrames(pf, pf); - w.computeFrame(mTestDisplayFrames); - assertFrame(w, winRect.left, 0, winRect.right, winRect.height()); - - // Now we have status bar. Check that it won't go into the status bar area. - final Rect statusBarFrame = new Rect(state.getDisplayFrame()); - statusBarFrame.bottom = 60; - state.getSource(ITYPE_STATUS_BAR).setFrame(statusBarFrame); - w.getWindowFrames().setFrames(pf, pf); - w.computeFrame(mTestDisplayFrames); - assertFrame(w, winRect.left, statusBarFrame.bottom, winRect.right, - statusBarFrame.bottom + winRect.height()); - - // Check that it's moved back without ime insets - state.removeSource(ITYPE_IME); - w.getWindowFrames().setFrames(pf, pf); - w.computeFrame(mTestDisplayFrames); - assertEquals(winRect, w.getFrame()); - } - - private WindowState createWindow() { - final WindowState ws = createWindow(null, TYPE_APPLICATION, mTestDisplayContent, "WindowFrameTests"); - spyOn(ws); - return ws; - } -} diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java new file mode 100644 index 000000000000..117f2ff96922 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import static android.view.WindowLayout.UNSPECIFIED_LENGTH; + +import static org.junit.Assert.assertEquals; + +import android.app.WindowConfiguration; +import android.graphics.Rect; +import android.platform.test.annotations.Presubmit; +import android.view.Gravity; +import android.view.InsetsState; +import android.view.InsetsVisibilities; +import android.view.WindowLayout; +import android.view.WindowManager; + +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; + +/** + * Tests for the {@link WindowLayout#computeWindowFrames}. + * + * Build/Install/Run: + * atest WmTests:WindowLayoutTests + */ +@SmallTest +@Presubmit +public class WindowLayoutTests { + private static final int DISPLAY_WIDTH = 500; + private static final int DISPLAY_HEIGHT = 1000; + private static final int STATUS_BAR_HEIGHT = 10; + private static final int NAVIGATION_BAR_HEIGHT = 15; + + private final WindowLayout mWindowLayout = new WindowLayout(); + private final Rect mDisplayFrame = new Rect(); + private final Rect mParentFrame = new Rect(); + private final Rect mFrame = new Rect(); + + private WindowManager.LayoutParams mAttrs; + private InsetsState mState; + private final Rect mDisplayCutoutSafe = new Rect(); + private Rect mWindowBounds; + private int mWindowingMode; + private int mRequestedWidth; + private int mRequestedHeight; + private InsetsVisibilities mRequestedVisibilities; + private Rect mAttachedWindowFrame; + private float mCompatScale; + + @Before + public void setUp() { + mAttrs = new WindowManager.LayoutParams(); + mState = new InsetsState(); + mState.setDisplayFrame(new Rect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT)); + mState.getSource(InsetsState.ITYPE_STATUS_BAR).setFrame( + 0, 0, DISPLAY_WIDTH, STATUS_BAR_HEIGHT); + mState.getSource(InsetsState.ITYPE_NAVIGATION_BAR).setFrame( + 0, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT); + mState.getDisplayCutoutSafe(mDisplayCutoutSafe); + mWindowBounds = new Rect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT); + mWindowingMode = WindowConfiguration.WINDOWING_MODE_FULLSCREEN; + mRequestedWidth = DISPLAY_WIDTH; + mRequestedHeight = DISPLAY_HEIGHT; + mRequestedVisibilities = new InsetsVisibilities(); + mAttachedWindowFrame = null; + mCompatScale = 1f; + } + + @Test + public void testDefaultLayoutParams() { + computeWindowFrames(); + + assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, + mDisplayFrame); + assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, + mParentFrame); + assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, + mFrame); + } + + @Test + public void testUnmeasured() { + mRequestedWidth = UNSPECIFIED_LENGTH; + mRequestedHeight = UNSPECIFIED_LENGTH; + computeWindowFrames(); + + assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, + mDisplayFrame); + assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, + mParentFrame); + assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, + mFrame); + } + + @Test + public void testUnmeasuredWithSizeSpecifiedInLayoutParams() { + final int width = DISPLAY_WIDTH / 2; + final int height = DISPLAY_HEIGHT / 2; + mRequestedWidth = UNSPECIFIED_LENGTH; + mRequestedHeight = UNSPECIFIED_LENGTH; + mAttrs.width = width; + mAttrs.height = height; + mAttrs.gravity = Gravity.LEFT | Gravity.TOP; + computeWindowFrames(); + + assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, + mDisplayFrame); + assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, + mParentFrame); + assertRect(0, STATUS_BAR_HEIGHT, width, STATUS_BAR_HEIGHT + height, + mFrame); + } + + @Test + public void testNonFullscreenWindowBounds() { + final int top = Math.max(DISPLAY_HEIGHT / 2, STATUS_BAR_HEIGHT); + mWindowBounds.set(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT); + mRequestedWidth = UNSPECIFIED_LENGTH; + mRequestedHeight = UNSPECIFIED_LENGTH; + computeWindowFrames(); + + assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, + mDisplayFrame); + assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, + mParentFrame); + assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, + mFrame); + } + + // TODO(b/161810301): Move tests here from DisplayPolicyLayoutTests and add more tests. + + private void computeWindowFrames() { + mWindowLayout.computeWindowFrames(mAttrs, mState, mDisplayCutoutSafe, mWindowBounds, + mWindowingMode, mRequestedWidth, mRequestedHeight, mRequestedVisibilities, + mAttachedWindowFrame, mCompatScale, mDisplayFrame, mParentFrame, mFrame); + } + + private void assertRect(int left, int top, int right, int bottom, Rect actual) { + assertEquals(new Rect(left, top, right, bottom), actual); + } +} 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 ac61bb15ab06..056a07a77068 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -285,8 +285,6 @@ class WindowTestsBase extends SystemServiceTestsBase { mStatusBarWindow.mAttrs.gravity = Gravity.TOP; mStatusBarWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; - mStatusBarWindow.setRequestedSize(WindowManager.LayoutParams.MATCH_PARENT, - STATUS_BAR_HEIGHT); } } if (addAll || ArrayUtils.contains(requestedWindows, W_NOTIFICATION_SHADE)) { diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java index 7a424c87d1d6..10fba60d4c95 100644 --- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java +++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java @@ -650,7 +650,13 @@ public final class TelephonyPermissions { private static boolean checkCarrierPrivilegeForAnySubId(Context context, int uid) { SubscriptionManager sm = (SubscriptionManager) context.getSystemService( Context.TELEPHONY_SUBSCRIPTION_SERVICE); - int[] activeSubIds = sm.getCompleteActiveSubscriptionIdList(); + int[] activeSubIds; + final long identity = Binder.clearCallingIdentity(); + try { + activeSubIds = sm.getCompleteActiveSubscriptionIdList(); + } finally { + Binder.restoreCallingIdentity(identity); + } for (int activeSubId : activeSubIds) { if (getCarrierPrivilegeStatus(context, activeSubId, uid) == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { |